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, TypeSpec parameterType)
545 if (Attribute.IsValidArgumentType (parameterType)) {
546 rc.Module.Compiler.Report.Error (182, loc,
547 "An attribute argument must be a constant expression, typeof expression or array creation expression");
549 rc.Module.Compiler.Report.Error (181, loc,
550 "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
551 targetType.GetSignatureForError ());
556 /// Emits the code for the expression
560 /// The Emit method is invoked to generate the code
561 /// for the expression.
563 public abstract void Emit (EmitContext ec);
566 // Emit code to branch to @target if this expression is equivalent to @on_true.
567 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
568 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
569 // including the use of conditional branches. Note also that a branch MUST be emitted
570 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
573 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
576 // Emit this expression for its side effects, not for its value.
577 // The default implementation is to emit the value, and then throw it away.
578 // Subclasses can provide more efficient implementations, but those MUST be equivalent
579 public virtual void EmitSideEffect (EmitContext ec)
582 ec.Emit (OpCodes.Pop);
586 // Emits the expression into temporary field variable. The method
587 // should be used for await expressions only
589 public virtual Expression EmitToField (EmitContext ec)
592 // This is the await prepare Emit method. When emitting code like
593 // a + b we emit code like
599 // For await a + await b we have to interfere the flow to keep the
600 // stack clean because await yields from the expression. The emit
603 // a = a.EmitToField () // a is changed to temporary field access
604 // b = b.EmitToField ()
610 // The idea is to emit expression and leave the stack empty with
611 // result value still available.
613 // Expressions should override this default implementation when
614 // optimized version can be provided (e.g. FieldExpr)
617 // We can optimize for side-effect free expressions, they can be
618 // emitted out of order
620 if (IsSideEffectFree)
623 bool needs_temporary = ContainsEmitWithAwait ();
624 if (!needs_temporary)
627 // Emit original code
628 var field = EmitToFieldSource (ec);
631 // Store the result to temporary field when we
632 // cannot load `this' directly
634 field = ec.GetTemporaryField (type);
635 if (needs_temporary) {
637 // Create temporary local (we cannot load `this' before Emit)
639 var temp = ec.GetTemporaryLocal (type);
640 ec.Emit (OpCodes.Stloc, temp);
643 ec.Emit (OpCodes.Ldloc, temp);
644 field.EmitAssignFromStack (ec);
646 ec.FreeTemporaryLocal (temp, type);
648 field.EmitAssignFromStack (ec);
655 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
658 // Default implementation calls Emit method
664 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
666 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
667 bool contains_await = false;
669 for (int i = 1; i < expressions.Count; ++i) {
670 if (expressions[i].ContainsEmitWithAwait ()) {
671 contains_await = true;
676 if (contains_await) {
677 for (int i = 0; i < expressions.Count; ++i) {
678 expressions[i] = expressions[i].EmitToField (ec);
683 for (int i = 0; i < expressions.Count; ++i) {
684 expressions[i].Emit (ec);
689 /// Protected constructor. Only derivate types should
690 /// be able to be created
693 protected Expression ()
698 /// Returns a fully formed expression after a MemberLookup
701 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
703 if (spec is EventSpec)
704 return new EventExpr ((EventSpec) spec, loc);
705 if (spec is ConstSpec)
706 return new ConstantExpr ((ConstSpec) spec, loc);
707 if (spec is FieldSpec)
708 return new FieldExpr ((FieldSpec) spec, loc);
709 if (spec is PropertySpec)
710 return new PropertyExpr ((PropertySpec) spec, loc);
711 if (spec is TypeSpec)
712 return new TypeExpression (((TypeSpec) spec), loc);
717 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
719 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
722 case MemberKind.Struct:
723 rc.Report.SymbolRelatedToPreviousError (type);
724 // Report meaningful error for struct as they always have default ctor in C# context
725 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
727 case MemberKind.MissingType:
728 case MemberKind.InternalCompilerType:
731 rc.Report.SymbolRelatedToPreviousError (type);
732 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
733 type.GetSignatureForError ());
740 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
741 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
742 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
745 return r.ResolveMember<MethodSpec> (rc, ref args);
749 public enum MemberLookupRestrictions
758 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
759 // `qualifier_type' or null to lookup members in the current class.
761 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
763 var members = MemberCache.FindMembers (queried_type, name, false);
767 MemberSpec non_method = null;
768 MemberSpec ambig_non_method = null;
770 for (int i = 0; i < members.Count; ++i) {
771 var member = members[i];
773 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
774 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
777 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
780 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
784 if (!member.IsAccessible (rc))
788 // With runtime binder we can have a situation where queried type is inaccessible
789 // because it came via dynamic object, the check about inconsisted accessibility
790 // had no effect as the type was unknown during compilation
793 // private class N { }
795 // public dynamic Foo ()
801 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
805 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
806 if (member is MethodSpec) {
808 // Interface members that are hidden by class members are removed from the set. This
809 // step only has an effect if T is a type parameter and T has both an effective base
810 // class other than object and a non-empty effective interface set
812 var tps = queried_type as TypeParameterSpec;
813 if (tps != null && tps.HasTypeConstraint)
814 members = RemoveHiddenTypeParameterMethods (members);
816 return new MethodGroupExpr (members, queried_type, loc);
819 if (!Invocation.IsMemberInvocable (member))
823 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
825 } else if (!errorMode && !member.IsNotCSharpCompatible) {
827 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
828 // T has both an effective base class other than object and a non-empty effective interface set.
830 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
832 var tps = queried_type as TypeParameterSpec;
833 if (tps != null && tps.HasTypeConstraint) {
834 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
837 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
843 ambig_non_method = member;
847 if (non_method != null) {
848 if (ambig_non_method != null && rc != null) {
849 var report = rc.Module.Compiler.Report;
850 report.SymbolRelatedToPreviousError (non_method);
851 report.SymbolRelatedToPreviousError (ambig_non_method);
852 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
853 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
856 if (non_method is MethodSpec)
857 return new MethodGroupExpr (members, queried_type, loc);
859 return ExprClassFromMemberInfo (non_method, loc);
862 if (members[0].DeclaringType.BaseType == null)
865 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
867 } while (members != null);
872 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
874 if (members.Count < 2)
878 // If M is a method, then all non-method members declared in an interface declaration
879 // are removed from the set, and all methods with the same signature as M declared in
880 // an interface declaration are removed from the set
884 for (int i = 0; i < members.Count; ++i) {
885 var method = members[i] as MethodSpec;
886 if (method == null) {
889 members = new List<MemberSpec> (members);
892 members.RemoveAt (i--);
896 if (!method.DeclaringType.IsInterface)
899 for (int ii = 0; ii < members.Count; ++ii) {
900 var candidate = members[ii] as MethodSpec;
901 if (candidate == null || !candidate.DeclaringType.IsClass)
904 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
909 members = new List<MemberSpec> (members);
912 members.RemoveAt (i--);
920 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
922 throw new NotImplementedException ();
925 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
927 if (t == InternalType.ErrorType)
930 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
931 oper, t.GetSignatureForError ());
934 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
936 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
939 public virtual void FlowAnalysis (FlowAnalysisContext fc)
944 /// Returns an expression that can be used to invoke operator true
945 /// on the expression if it exists.
947 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
949 return GetOperatorTrueOrFalse (ec, e, true, loc);
953 /// Returns an expression that can be used to invoke operator false
954 /// on the expression if it exists.
956 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
958 return GetOperatorTrueOrFalse (ec, e, false, loc);
961 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
963 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
964 var methods = MemberCache.GetUserOperator (e.type, op, false);
968 Arguments arguments = new Arguments (1);
969 arguments.Add (new Argument (e));
971 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
972 var oper = res.ResolveOperator (ec, ref arguments);
977 return new UserOperatorCall (oper, arguments, null, loc);
980 public virtual string ExprClassName
984 case ExprClass.Unresolved:
986 case ExprClass.Value:
988 case ExprClass.Variable:
990 case ExprClass.Namespace:
994 case ExprClass.MethodGroup:
995 return "method group";
996 case ExprClass.PropertyAccess:
997 return "property access";
998 case ExprClass.EventAccess:
999 return "event access";
1000 case ExprClass.IndexerAccess:
1001 return "indexer access";
1002 case ExprClass.Nothing:
1004 case ExprClass.TypeParameter:
1005 return "type parameter";
1007 throw new Exception ("Should not happen");
1012 /// Reports that we were expecting `expr' to be of class `expected'
1014 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1016 var name = memberExpr.GetSignatureForError ();
1018 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1021 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1023 string [] valid = new string [4];
1026 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1027 valid [count++] = "variable";
1028 valid [count++] = "value";
1031 if ((flags & ResolveFlags.Type) != 0)
1032 valid [count++] = "type";
1034 if ((flags & ResolveFlags.MethodGroup) != 0)
1035 valid [count++] = "method group";
1038 valid [count++] = "unknown";
1040 StringBuilder sb = new StringBuilder (valid [0]);
1041 for (int i = 1; i < count - 1; i++) {
1043 sb.Append (valid [i]);
1046 sb.Append ("' or `");
1047 sb.Append (valid [count - 1]);
1050 ec.Report.Error (119, loc,
1051 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1054 public static void UnsafeError (ResolveContext ec, Location loc)
1056 UnsafeError (ec.Report, loc);
1059 public static void UnsafeError (Report Report, Location loc)
1061 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1065 // Converts `source' to an int, uint, long or ulong.
1067 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1069 var btypes = ec.BuiltinTypes;
1071 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1072 Arguments args = new Arguments (1);
1073 args.Add (new Argument (source));
1074 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1077 Expression converted;
1079 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1080 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1081 if (converted == null)
1082 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1083 if (converted == null)
1084 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1085 if (converted == null)
1086 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1088 if (converted == null) {
1089 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1098 // Only positive constants are allowed at compile time
1100 Constant c = converted as Constant;
1101 if (c != null && c.IsNegative)
1102 Error_NegativeArrayIndex (ec, source.loc);
1104 // No conversion needed to array index
1105 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1108 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1112 // Derived classes implement this method by cloning the fields that
1113 // could become altered during the Resolve stage
1115 // Only expressions that are created for the parser need to implement
1118 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1120 throw new NotImplementedException (
1122 "CloneTo not implemented for expression {0}", this.GetType ()));
1126 // Clones an expression created by the parser.
1128 // We only support expressions created by the parser so far, not
1129 // expressions that have been resolved (many more classes would need
1130 // to implement CloneTo).
1132 // This infrastructure is here merely for Lambda expressions which
1133 // compile the same code using different type values for the same
1134 // arguments to find the correct overload
1136 public virtual Expression Clone (CloneContext clonectx)
1138 Expression cloned = (Expression) MemberwiseClone ();
1139 CloneTo (clonectx, cloned);
1145 // Implementation of expression to expression tree conversion
1147 public abstract Expression CreateExpressionTree (ResolveContext ec);
1149 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1151 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1154 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1156 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1159 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1161 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1164 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1166 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1170 return new TypeExpression (t, loc);
1174 // Implemented by all expressions which support conversion from
1175 // compiler expression to invokable runtime expression. Used by
1176 // dynamic C# binder.
1178 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1180 throw new NotImplementedException ("MakeExpression for " + GetType ());
1183 public virtual object Accept (StructuralVisitor visitor)
1185 return visitor.Visit (this);
1190 /// This is just a base class for expressions that can
1191 /// appear on statements (invocations, object creation,
1192 /// assignments, post/pre increment and decrement). The idea
1193 /// being that they would support an extra Emition interface that
1194 /// does not leave a result on the stack.
1196 public abstract class ExpressionStatement : Expression
1198 public virtual void MarkReachable (Reachability rc)
1202 public ExpressionStatement ResolveStatement (BlockContext ec)
1204 Expression e = Resolve (ec);
1208 ExpressionStatement es = e as ExpressionStatement;
1209 if (es == null || e is AnonymousMethodBody)
1210 Error_InvalidExpressionStatement (ec);
1213 // This is quite expensive warning, try to limit the damage
1215 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1216 WarningAsyncWithoutWait (ec, e);
1222 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1224 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1225 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1230 // Need to do full resolve because GetAwaiter can be extension method
1231 // available only in this context
1233 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1237 var arguments = new Arguments (0);
1238 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1243 // Use same check rules as for real await
1245 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1246 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1249 bc.Report.Warning (4014, 1, e.Location,
1250 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1254 var inv = e as Invocation;
1255 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1256 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1257 bc.Report.Warning (4014, 1, e.Location,
1258 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1264 /// Requests the expression to be emitted in a `statement'
1265 /// context. This means that no new value is left on the
1266 /// stack after invoking this method (constrasted with
1267 /// Emit that will always leave a value on the stack).
1269 public abstract void EmitStatement (EmitContext ec);
1271 public override void EmitSideEffect (EmitContext ec)
1278 /// This kind of cast is used to encapsulate the child
1279 /// whose type is child.Type into an expression that is
1280 /// reported to return "return_type". This is used to encapsulate
1281 /// expressions which have compatible types, but need to be dealt
1282 /// at higher levels with.
1284 /// For example, a "byte" expression could be encapsulated in one
1285 /// of these as an "unsigned int". The type for the expression
1286 /// would be "unsigned int".
1289 public abstract class TypeCast : Expression
1291 protected readonly Expression child;
1293 protected TypeCast (Expression child, TypeSpec return_type)
1295 eclass = child.eclass;
1296 loc = child.Location;
1301 public Expression Child {
1307 public override bool ContainsEmitWithAwait ()
1309 return child.ContainsEmitWithAwait ();
1312 public override Expression CreateExpressionTree (ResolveContext ec)
1314 Arguments args = new Arguments (2);
1315 args.Add (new Argument (child.CreateExpressionTree (ec)));
1316 args.Add (new Argument (new TypeOf (type, loc)));
1318 if (type.IsPointer || child.Type.IsPointer)
1319 Error_PointerInsideExpressionTree (ec);
1321 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1324 protected override Expression DoResolve (ResolveContext ec)
1326 // This should never be invoked, we are born in fully
1327 // initialized state.
1332 public override void Emit (EmitContext ec)
1337 public override void FlowAnalysis (FlowAnalysisContext fc)
1339 child.FlowAnalysis (fc);
1342 public override SLE.Expression MakeExpression (BuilderContext ctx)
1345 return base.MakeExpression (ctx);
1347 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1348 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1349 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1353 protected override void CloneTo (CloneContext clonectx, Expression t)
1358 public override bool IsNull {
1359 get { return child.IsNull; }
1363 public class EmptyCast : TypeCast {
1364 EmptyCast (Expression child, TypeSpec target_type)
1365 : base (child, target_type)
1369 public static Expression Create (Expression child, TypeSpec type)
1371 Constant c = child as Constant;
1373 var enum_constant = c as EnumConstant;
1374 if (enum_constant != null)
1375 c = enum_constant.Child;
1377 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1381 var res = c.ConvertImplicitly (type);
1387 EmptyCast e = child as EmptyCast;
1389 return new EmptyCast (e.child, type);
1391 return new EmptyCast (child, type);
1394 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1396 child.EmitBranchable (ec, label, on_true);
1399 public override void EmitSideEffect (EmitContext ec)
1401 child.EmitSideEffect (ec);
1406 // Used for predefined type user operator (no obsolete check, etc.)
1408 public class OperatorCast : TypeCast
1410 readonly MethodSpec conversion_operator;
1412 public OperatorCast (Expression expr, TypeSpec target_type)
1413 : this (expr, target_type, target_type, false)
1417 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1418 : this (expr, target_type, target_type, find_explicit)
1422 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1423 : base (expr, returnType)
1425 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1426 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1429 foreach (MethodSpec oper in mi) {
1430 if (oper.ReturnType != returnType)
1433 if (oper.Parameters.Types[0] == expr.Type) {
1434 conversion_operator = oper;
1440 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1441 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1444 public override void Emit (EmitContext ec)
1447 ec.Emit (OpCodes.Call, conversion_operator);
1452 // Constant specialization of EmptyCast.
1453 // We need to special case this since an empty cast of
1454 // a constant is still a constant.
1456 public class EmptyConstantCast : Constant
1458 public readonly Constant child;
1460 public EmptyConstantCast (Constant child, TypeSpec type)
1461 : base (child.Location)
1464 throw new ArgumentNullException ("child");
1467 this.eclass = child.eclass;
1471 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1473 if (child.Type == target_type)
1476 // FIXME: check that 'type' can be converted to 'target_type' first
1477 return child.ConvertExplicitly (in_checked_context, target_type);
1480 public override Expression CreateExpressionTree (ResolveContext ec)
1482 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1483 child.CreateExpressionTree (ec),
1484 new TypeOf (type, loc));
1487 Error_PointerInsideExpressionTree (ec);
1489 return CreateExpressionFactoryCall (ec, "Convert", args);
1492 public override bool IsDefaultValue {
1493 get { return child.IsDefaultValue; }
1496 public override bool IsNegative {
1497 get { return child.IsNegative; }
1500 public override bool IsNull {
1501 get { return child.IsNull; }
1504 public override bool IsOneInteger {
1505 get { return child.IsOneInteger; }
1508 public override bool IsSideEffectFree {
1510 return child.IsSideEffectFree;
1514 public override bool IsZeroInteger {
1515 get { return child.IsZeroInteger; }
1518 public override void Emit (EmitContext ec)
1523 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1525 child.EmitBranchable (ec, label, on_true);
1527 // Only to make verifier happy
1528 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1529 ec.Emit (OpCodes.Unbox_Any, type);
1532 public override void EmitSideEffect (EmitContext ec)
1534 child.EmitSideEffect (ec);
1537 public override object GetValue ()
1539 return child.GetValue ();
1542 public override string GetValueAsLiteral ()
1544 return child.GetValueAsLiteral ();
1547 public override long GetValueAsLong ()
1549 return child.GetValueAsLong ();
1552 public override Constant ConvertImplicitly (TypeSpec target_type)
1554 if (type == target_type)
1557 // FIXME: Do we need to check user conversions?
1558 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1561 return child.ConvertImplicitly (target_type);
1566 /// This class is used to wrap literals which belong inside Enums
1568 public class EnumConstant : Constant
1570 public Constant Child;
1572 public EnumConstant (Constant child, TypeSpec enum_type)
1573 : base (child.Location)
1577 this.eclass = ExprClass.Value;
1578 this.type = enum_type;
1581 protected EnumConstant (Location loc)
1586 public override void Emit (EmitContext ec)
1591 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1593 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1596 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1598 Child.EmitBranchable (ec, label, on_true);
1601 public override void EmitSideEffect (EmitContext ec)
1603 Child.EmitSideEffect (ec);
1606 public override string GetSignatureForError()
1608 return Type.GetSignatureForError ();
1611 public override object GetValue ()
1613 return Child.GetValue ();
1617 public override object GetTypedValue ()
1620 // The method can be used in dynamic context only (on closed types)
1622 // System.Enum.ToObject cannot be called on dynamic types
1623 // EnumBuilder has to be used, but we cannot use EnumBuilder
1624 // because it does not properly support generics
1626 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1630 public override string GetValueAsLiteral ()
1632 return Child.GetValueAsLiteral ();
1635 public override long GetValueAsLong ()
1637 return Child.GetValueAsLong ();
1640 public EnumConstant Increment()
1642 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1645 public override bool IsDefaultValue {
1647 return Child.IsDefaultValue;
1651 public override bool IsSideEffectFree {
1653 return Child.IsSideEffectFree;
1657 public override bool IsZeroInteger {
1658 get { return Child.IsZeroInteger; }
1661 public override bool IsNegative {
1663 return Child.IsNegative;
1667 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1669 if (Child.Type == target_type)
1672 return Child.ConvertExplicitly (in_checked_context, target_type);
1675 public override Constant ConvertImplicitly (TypeSpec type)
1677 if (this.type == type) {
1681 if (!Convert.ImplicitStandardConversionExists (this, type)){
1685 return Child.ConvertImplicitly (type);
1690 /// This kind of cast is used to encapsulate Value Types in objects.
1692 /// The effect of it is to box the value type emitted by the previous
1695 public class BoxedCast : TypeCast {
1697 public BoxedCast (Expression expr, TypeSpec target_type)
1698 : base (expr, target_type)
1700 eclass = ExprClass.Value;
1703 protected override Expression DoResolve (ResolveContext ec)
1705 // This should never be invoked, we are born in fully
1706 // initialized state.
1711 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1713 // Only boxing to object type is supported
1714 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1715 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1719 enc.Encode (child.Type);
1720 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1723 public override void Emit (EmitContext ec)
1727 ec.Emit (OpCodes.Box, child.Type);
1730 public override void EmitSideEffect (EmitContext ec)
1732 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1733 // so, we need to emit the box+pop instructions in most cases
1734 if (child.Type.IsStruct &&
1735 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1736 child.EmitSideEffect (ec);
1738 base.EmitSideEffect (ec);
1742 public class UnboxCast : TypeCast {
1743 public UnboxCast (Expression expr, TypeSpec return_type)
1744 : base (expr, return_type)
1748 protected override Expression DoResolve (ResolveContext ec)
1750 // This should never be invoked, we are born in fully
1751 // initialized state.
1756 public override void Emit (EmitContext ec)
1760 ec.Emit (OpCodes.Unbox_Any, type);
1765 /// This is used to perform explicit numeric conversions.
1767 /// Explicit numeric conversions might trigger exceptions in a checked
1768 /// context, so they should generate the conv.ovf opcodes instead of
1771 public class ConvCast : TypeCast {
1772 public enum Mode : byte {
1773 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1775 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1776 U2_I1, U2_U1, U2_I2, U2_CH,
1777 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1778 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1779 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1780 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1781 CH_I1, CH_U1, CH_I2,
1782 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1783 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1789 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1790 : base (child, return_type)
1795 protected override Expression DoResolve (ResolveContext ec)
1797 // This should never be invoked, we are born in fully
1798 // initialized state.
1803 public override string ToString ()
1805 return String.Format ("ConvCast ({0}, {1})", mode, child);
1808 public override void Emit (EmitContext ec)
1814 public static void Emit (EmitContext ec, Mode mode)
1816 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1818 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1819 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1820 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1821 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1822 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1824 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1825 case Mode.U1_CH: /* nothing */ break;
1827 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1828 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1829 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1830 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1831 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1832 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1834 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1835 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1836 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1837 case Mode.U2_CH: /* nothing */ break;
1839 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1840 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1841 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1842 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1843 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1844 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1845 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1847 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1848 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1849 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1850 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1851 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1852 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1854 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1855 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1856 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1857 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1858 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1859 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1860 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1861 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1862 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1864 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1865 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1866 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1867 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1868 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1869 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1870 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1871 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1872 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1874 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1875 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1876 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1878 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1879 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1880 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1881 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1882 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1883 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1884 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1885 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1886 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1888 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1889 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1890 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1891 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1892 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1893 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1894 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1895 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1896 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1897 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1899 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1903 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1904 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1905 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1906 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1907 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1909 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1910 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1912 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1913 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1914 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1915 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1916 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1917 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1919 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1920 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1921 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1922 case Mode.U2_CH: /* nothing */ break;
1924 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1925 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1926 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1927 case Mode.I4_U4: /* nothing */ break;
1928 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1929 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1930 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1932 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1933 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1934 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1935 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1936 case Mode.U4_I4: /* nothing */ break;
1937 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1939 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1940 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1941 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1942 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1943 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1944 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1945 case Mode.I8_U8: /* nothing */ break;
1946 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1947 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1949 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1950 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1951 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1952 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1953 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1954 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1955 case Mode.U8_I8: /* nothing */ break;
1956 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1957 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1959 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1960 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1961 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1963 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1964 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1965 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1966 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1967 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1968 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1969 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1970 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1971 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1973 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1974 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1975 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1976 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1977 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1978 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1979 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1980 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1981 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1982 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1984 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1990 class OpcodeCast : TypeCast
1994 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1995 : base (child, return_type)
2000 protected override Expression DoResolve (ResolveContext ec)
2002 // This should never be invoked, we are born in fully
2003 // initialized state.
2008 public override void Emit (EmitContext ec)
2014 public TypeSpec UnderlyingType {
2015 get { return child.Type; }
2020 // Opcode casts expression with 2 opcodes but only
2021 // single expression tree node
2023 class OpcodeCastDuplex : OpcodeCast
2025 readonly OpCode second;
2027 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2028 : base (child, returnType, first)
2030 this.second = second;
2033 public override void Emit (EmitContext ec)
2041 /// This kind of cast is used to encapsulate a child and cast it
2042 /// to the class requested
2044 public sealed class ClassCast : TypeCast {
2045 readonly bool forced;
2047 public ClassCast (Expression child, TypeSpec return_type)
2048 : base (child, return_type)
2052 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2053 : base (child, return_type)
2055 this.forced = forced;
2058 public override void Emit (EmitContext ec)
2062 bool gen = TypeManager.IsGenericParameter (child.Type);
2064 ec.Emit (OpCodes.Box, child.Type);
2066 if (type.IsGenericParameter) {
2067 ec.Emit (OpCodes.Unbox_Any, type);
2074 ec.Emit (OpCodes.Castclass, type);
2079 // Created during resolving pahse when an expression is wrapped or constantified
2080 // and original expression can be used later (e.g. for expression trees)
2082 public class ReducedExpression : Expression
2084 public sealed class ReducedConstantExpression : EmptyConstantCast
2086 readonly Expression orig_expr;
2088 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2089 : base (expr, expr.Type)
2091 this.orig_expr = orig_expr;
2094 public Expression OriginalExpression {
2100 public override Constant ConvertImplicitly (TypeSpec target_type)
2102 Constant c = base.ConvertImplicitly (target_type);
2104 c = new ReducedConstantExpression (c, orig_expr);
2109 public override Expression CreateExpressionTree (ResolveContext ec)
2111 return orig_expr.CreateExpressionTree (ec);
2114 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2116 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2118 c = new ReducedConstantExpression (c, orig_expr);
2122 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2125 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2127 if (orig_expr is Conditional)
2128 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2130 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2134 sealed class ReducedExpressionStatement : ExpressionStatement
2136 readonly Expression orig_expr;
2137 readonly ExpressionStatement stm;
2139 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2141 this.orig_expr = orig;
2143 this.eclass = stm.eclass;
2144 this.type = stm.Type;
2146 this.loc = orig.Location;
2149 public override bool ContainsEmitWithAwait ()
2151 return stm.ContainsEmitWithAwait ();
2154 public override Expression CreateExpressionTree (ResolveContext ec)
2156 return orig_expr.CreateExpressionTree (ec);
2159 protected override Expression DoResolve (ResolveContext ec)
2164 public override void Emit (EmitContext ec)
2169 public override void EmitStatement (EmitContext ec)
2171 stm.EmitStatement (ec);
2174 public override void FlowAnalysis (FlowAnalysisContext fc)
2176 stm.FlowAnalysis (fc);
2180 readonly Expression expr, orig_expr;
2182 private ReducedExpression (Expression expr, Expression orig_expr)
2185 this.eclass = expr.eclass;
2186 this.type = expr.Type;
2187 this.orig_expr = orig_expr;
2188 this.loc = orig_expr.Location;
2193 public override bool IsSideEffectFree {
2195 return expr.IsSideEffectFree;
2199 public Expression OriginalExpression {
2207 public override bool ContainsEmitWithAwait ()
2209 return expr.ContainsEmitWithAwait ();
2213 // Creates fully resolved expression switcher
2215 public static Constant Create (Constant expr, Expression original_expr)
2217 if (expr.eclass == ExprClass.Unresolved)
2218 throw new ArgumentException ("Unresolved expression");
2220 return new ReducedConstantExpression (expr, original_expr);
2223 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2225 return new ReducedExpressionStatement (s, orig);
2228 public static Expression Create (Expression expr, Expression original_expr)
2230 return Create (expr, original_expr, true);
2234 // Creates unresolved reduce expression. The original expression has to be
2235 // already resolved. Created expression is constant based based on `expr'
2236 // value unless canBeConstant is used
2238 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2240 if (canBeConstant) {
2241 Constant c = expr as Constant;
2243 return Create (c, original_expr);
2246 ExpressionStatement s = expr as ExpressionStatement;
2248 return Create (s, original_expr);
2250 if (expr.eclass == ExprClass.Unresolved)
2251 throw new ArgumentException ("Unresolved expression");
2253 return new ReducedExpression (expr, original_expr);
2256 public override Expression CreateExpressionTree (ResolveContext ec)
2258 return orig_expr.CreateExpressionTree (ec);
2261 protected override Expression DoResolve (ResolveContext ec)
2266 public override void Emit (EmitContext ec)
2271 public override Expression EmitToField (EmitContext ec)
2273 return expr.EmitToField(ec);
2276 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2278 expr.EmitBranchable (ec, target, on_true);
2281 public override void FlowAnalysis (FlowAnalysisContext fc)
2283 expr.FlowAnalysis (fc);
2286 public override SLE.Expression MakeExpression (BuilderContext ctx)
2288 return orig_expr.MakeExpression (ctx);
2293 // Standard composite pattern
2295 public abstract class CompositeExpression : Expression
2297 protected Expression expr;
2299 protected CompositeExpression (Expression expr)
2302 this.loc = expr.Location;
2305 public override bool ContainsEmitWithAwait ()
2307 return expr.ContainsEmitWithAwait ();
2310 public override Expression CreateExpressionTree (ResolveContext rc)
2312 return expr.CreateExpressionTree (rc);
2315 public Expression Child {
2316 get { return expr; }
2319 protected override Expression DoResolve (ResolveContext rc)
2321 expr = expr.Resolve (rc);
2326 eclass = expr.eclass;
2330 public override void Emit (EmitContext ec)
2335 public override bool IsNull {
2336 get { return expr.IsNull; }
2341 // Base of expressions used only to narrow resolve flow
2343 public abstract class ShimExpression : Expression
2345 protected Expression expr;
2347 protected ShimExpression (Expression expr)
2352 public Expression Expr {
2358 protected override void CloneTo (CloneContext clonectx, Expression t)
2363 ShimExpression target = (ShimExpression) t;
2364 target.expr = expr.Clone (clonectx);
2367 public override bool ContainsEmitWithAwait ()
2369 return expr.ContainsEmitWithAwait ();
2372 public override Expression CreateExpressionTree (ResolveContext ec)
2374 throw new NotSupportedException ("ET");
2377 public override void Emit (EmitContext ec)
2379 throw new InternalErrorException ("Missing Resolve call");
2383 public class UnreachableExpression : Expression
2385 public UnreachableExpression (Expression expr)
2387 this.loc = expr.Location;
2390 public override Expression CreateExpressionTree (ResolveContext ec)
2393 throw new NotImplementedException ();
2396 protected override Expression DoResolve (ResolveContext rc)
2398 throw new NotSupportedException ();
2401 public override void FlowAnalysis (FlowAnalysisContext fc)
2403 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2406 public override void Emit (EmitContext ec)
2410 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2416 // Unresolved type name expressions
2418 public abstract class ATypeNameExpression : FullNamedExpression
2421 protected TypeArguments targs;
2423 protected ATypeNameExpression (string name, Location l)
2429 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2436 protected ATypeNameExpression (string name, int arity, Location l)
2437 : this (name, new UnboundTypeArguments (arity), l)
2443 protected int Arity {
2445 return targs == null ? 0 : targs.Count;
2449 public bool HasTypeArguments {
2451 return targs != null && !targs.IsEmpty;
2455 public string Name {
2464 public TypeArguments TypeArguments {
2472 public override bool Equals (object obj)
2474 ATypeNameExpression atne = obj as ATypeNameExpression;
2475 return atne != null && atne.Name == Name &&
2476 (targs == null || targs.Equals (atne.targs));
2479 public override int GetHashCode ()
2481 return Name.GetHashCode ();
2484 // TODO: Move it to MemberCore
2485 public static string GetMemberType (MemberCore mc)
2491 if (mc is FieldBase)
2493 if (mc is MethodCore)
2495 if (mc is EnumMember)
2503 public override string GetSignatureForError ()
2505 if (targs != null) {
2506 return Name + "<" + targs.GetSignatureForError () + ">";
2512 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2516 /// SimpleName expressions are formed of a single word and only happen at the beginning
2517 /// of a dotted-name.
2519 public class SimpleName : ATypeNameExpression
2521 public SimpleName (string name, Location l)
2526 public SimpleName (string name, TypeArguments args, Location l)
2527 : base (name, args, l)
2531 public SimpleName (string name, int arity, Location l)
2532 : base (name, arity, l)
2536 public SimpleName GetMethodGroup ()
2538 return new SimpleName (Name, targs, loc);
2541 protected override Expression DoResolve (ResolveContext rc)
2543 return SimpleNameResolve (rc, null);
2546 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2548 return SimpleNameResolve (ec, right_side);
2551 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2553 if (ctx.CurrentType != null) {
2554 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2555 if (member != null) {
2556 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2561 var report = ctx.Module.Compiler.Report;
2563 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2564 if (retval != null) {
2565 report.SymbolRelatedToPreviousError (retval.Type);
2566 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2570 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2571 if (retval != null) {
2572 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2576 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2577 if (ns_candidates != null) {
2578 if (ctx is UsingAliasNamespace.AliasContext) {
2579 report.Error (246, loc,
2580 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2581 ns_candidates[0], Name);
2583 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2584 report.Error (246, loc,
2585 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2589 report.Error (246, loc,
2590 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2595 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2597 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2600 if (fne.Type != null && Arity > 0) {
2601 if (HasTypeArguments) {
2602 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2603 if (ct.ResolveAsType (mc) == null)
2609 return new GenericOpenTypeExpr (fne.Type, loc);
2613 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2615 if (!(fne is NamespaceExpression))
2619 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2620 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2621 mc.Module.Compiler.Report.Error (1980, Location,
2622 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2623 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2626 fne = new DynamicTypeExpr (loc);
2627 fne.ResolveAsType (mc);
2633 Error_TypeOrNamespaceNotFound (mc);
2637 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2639 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2642 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2644 int lookup_arity = Arity;
2645 bool errorMode = false;
2647 Block current_block = rc.CurrentBlock;
2648 INamedBlockVariable variable = null;
2649 bool variable_found = false;
2653 // Stage 1: binding to local variables or parameters
2655 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2657 if (current_block != null && lookup_arity == 0) {
2658 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2659 if (!variable.IsDeclared) {
2660 // We found local name in accessible block but it's not
2661 // initialized yet, maybe the user wanted to bind to something else
2663 variable_found = true;
2665 e = variable.CreateReferenceExpression (rc, loc);
2668 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2677 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2679 TypeSpec member_type = rc.CurrentType;
2680 for (; member_type != null; member_type = member_type.DeclaringType) {
2681 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2685 var me = e as MemberExpr;
2687 // The name matches a type, defer to ResolveAsTypeStep
2695 if (variable != null) {
2696 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2697 rc.Report.Error (844, loc,
2698 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2699 Name, me.GetSignatureForError ());
2703 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2704 // Leave it to overload resolution to report correct error
2706 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2707 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2710 // LAMESPEC: again, ignores InvocableOnly
2711 if (variable != null) {
2712 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2713 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2717 // MemberLookup does not check accessors availability, this is actually needed for properties only
2719 var pe = me as PropertyExpr;
2722 // Break as there is no other overload available anyway
2723 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2724 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2727 pe.Getter = pe.PropertyInfo.Get;
2729 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2732 pe.Setter = pe.PropertyInfo.Set;
2737 // TODO: It's used by EventExpr -> FieldExpr transformation only
2738 // TODO: Should go to MemberAccess
2739 me = me.ResolveMemberAccess (rc, null, null);
2743 me.SetTypeArguments (rc, targs);
2750 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2752 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2753 if (IsPossibleTypeOrNamespace (rc)) {
2754 if (variable != null) {
2755 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2756 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2759 return ResolveAsTypeOrNamespace (rc);
2764 if (variable_found) {
2765 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2768 var tparams = rc.CurrentTypeParameters;
2769 if (tparams != null) {
2770 if (tparams.Find (Name) != null) {
2771 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2776 var ct = rc.CurrentType;
2778 if (ct.MemberDefinition.TypeParametersCount > 0) {
2779 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2780 if (ctp.Name == Name) {
2781 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2787 ct = ct.DeclaringType;
2788 } while (ct != null);
2790 var cos = rc.CurrentMemberDefinition.Parent as ClassOrStruct;
2791 if (cos != null && cos.PrimaryConstructorParameters != null) {
2792 foreach (var p in cos.PrimaryConstructorParameters.FixedParameters) {
2793 if (p.Name == Name) {
2794 rc.Report.Error (9007, loc, "Primary constructor parameter `{0}' is not available in this context when using ref or out modifier",
2802 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2803 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2805 rc.Report.SymbolRelatedToPreviousError (e.Type);
2806 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2810 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2812 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2813 return ErrorExpression.Instance;
2817 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2819 if (e.Type.Arity != Arity) {
2820 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2824 if (e is TypeExpr) {
2825 // TypeExpression does not have correct location
2826 if (e is TypeExpression)
2827 e = new TypeExpression (e.Type, loc);
2833 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2836 return ErrorExpression.Instance;
2839 if (rc.Module.Evaluator != null) {
2840 var fi = rc.Module.Evaluator.LookupField (Name);
2842 return new FieldExpr (fi.Item1, loc);
2850 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2852 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2857 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2858 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2862 if (right_side != null) {
2863 e = e.ResolveLValue (ec, right_side);
2871 public override object Accept (StructuralVisitor visitor)
2873 return visitor.Visit (this);
2878 /// Represents a namespace or a type. The name of the class was inspired by
2879 /// section 10.8.1 (Fully Qualified Names).
2881 public abstract class FullNamedExpression : Expression
2883 protected override void CloneTo (CloneContext clonectx, Expression target)
2885 // Do nothing, most unresolved type expressions cannot be
2886 // resolved to different type
2889 public override bool ContainsEmitWithAwait ()
2894 public override Expression CreateExpressionTree (ResolveContext ec)
2896 throw new NotSupportedException ("ET");
2899 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2902 // This is used to resolve the expression as a type, a null
2903 // value will be returned if the expression is not a type
2906 public override TypeSpec ResolveAsType (IMemberContext mc)
2908 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2913 TypeExpr te = fne as TypeExpr;
2915 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2923 var dep = type.GetMissingDependencies ();
2925 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2928 if (type.Kind == MemberKind.Void) {
2929 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2933 // Obsolete checks cannot be done when resolving base context as they
2934 // require type dependencies to be set but we are in process of resolving them
2936 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2937 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2938 if (obsolete_attr != null && !mc.IsObsolete) {
2939 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2947 public override void Emit (EmitContext ec)
2949 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2950 GetSignatureForError ());
2955 /// Expression that evaluates to a type
2957 public abstract class TypeExpr : FullNamedExpression
2959 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2965 protected sealed override Expression DoResolve (ResolveContext ec)
2971 public override bool Equals (object obj)
2973 TypeExpr tobj = obj as TypeExpr;
2977 return Type == tobj.Type;
2980 public override int GetHashCode ()
2982 return Type.GetHashCode ();
2987 /// Fully resolved Expression that already evaluated to a type
2989 public class TypeExpression : TypeExpr
2991 public TypeExpression (TypeSpec t, Location l)
2994 eclass = ExprClass.Type;
2998 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
3004 public class NamespaceExpression : FullNamedExpression
3006 readonly Namespace ns;
3008 public NamespaceExpression (Namespace ns, Location loc)
3011 this.Type = InternalType.Namespace;
3012 this.eclass = ExprClass.Namespace;
3016 public Namespace Namespace {
3022 protected override Expression DoResolve (ResolveContext rc)
3024 throw new NotImplementedException ();
3027 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
3032 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity)
3034 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3035 if (retval != null) {
3036 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3037 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3041 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3042 if (retval != null) {
3043 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3048 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3049 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3053 string assembly = null;
3054 string possible_name = Namespace.GetSignatureForError () + "." + name;
3056 // Only assembly unique name should be added
3057 switch (possible_name) {
3058 case "System.Drawing":
3059 case "System.Web.Services":
3062 case "System.Configuration":
3063 case "System.Data.Services":
3064 case "System.DirectoryServices":
3066 case "System.Net.Http":
3067 case "System.Numerics":
3068 case "System.Runtime.Caching":
3069 case "System.ServiceModel":
3070 case "System.Transactions":
3071 case "System.Web.Routing":
3072 case "System.Xml.Linq":
3074 assembly = possible_name;
3078 case "System.Linq.Expressions":
3079 assembly = "System.Core";
3082 case "System.Windows.Forms":
3083 case "System.Windows.Forms.Layout":
3084 assembly = "System.Windows.Forms";
3088 assembly = assembly == null ? "an" : "`" + assembly + "'";
3090 if (Namespace is GlobalRootNamespace) {
3091 ctx.Module.Compiler.Report.Error (400, loc,
3092 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3095 ctx.Module.Compiler.Report.Error (234, loc,
3096 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3097 name, GetSignatureForError (), assembly);
3101 public override string GetSignatureForError ()
3103 return ns.GetSignatureForError ();
3106 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3108 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3113 /// This class denotes an expression which evaluates to a member
3114 /// of a struct or a class.
3116 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3119 // An instance expression associated with this member, if it's a
3120 // non-static member
3122 public Expression InstanceExpression;
3125 /// The name of this member.
3127 public abstract string Name {
3132 // When base.member is used
3134 public bool IsBase {
3135 get { return InstanceExpression is BaseThis; }
3139 /// Whether this is an instance member.
3141 public abstract bool IsInstance {
3146 /// Whether this is a static member.
3148 public abstract bool IsStatic {
3152 public abstract string KindName {
3156 protected abstract TypeSpec DeclaringType {
3160 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3162 return InstanceExpression.Type;
3167 // Converts best base candidate for virtual method starting from QueriedBaseType
3169 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3172 // Only when base.member is used and method is virtual
3178 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3179 // means for base.member access we have to find the closest match after we found best candidate
3181 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3183 // The method could already be what we are looking for
3185 TypeSpec[] targs = null;
3186 if (method.DeclaringType != InstanceExpression.Type) {
3188 // Candidate can have inflated MVAR parameters and we need to find
3189 // base match for original definition not inflated parameter types
3191 var parameters = method.Parameters;
3192 if (method.Arity > 0) {
3193 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3194 var inflated = method.DeclaringType as InflatedTypeSpec;
3195 if (inflated != null) {
3196 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3200 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3201 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3202 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3203 if (base_override.IsGeneric)
3204 targs = method.TypeArguments;
3206 method = base_override;
3211 // When base access is used inside anonymous method/iterator/etc we need to
3212 // get back to the context of original type. We do it by emiting proxy
3213 // method in original class and rewriting base call to this compiler
3214 // generated method call which does the actual base invocation. This may
3215 // introduce redundant storey but with `this' only but it's tricky to avoid
3216 // at this stage as we don't know what expressions follow base
3218 if (rc.CurrentAnonymousMethod != null) {
3219 if (targs == null && method.IsGeneric) {
3220 targs = method.TypeArguments;
3221 method = method.GetGenericMethodDefinition ();
3224 if (method.Parameters.HasArglist)
3225 throw new NotImplementedException ("__arglist base call proxy");
3227 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3229 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3230 // get/set member expressions second call would fail to proxy because left expression
3231 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3232 // FIXME: The async check is another hack but will probably fail with mutators
3233 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3234 InstanceExpression = new This (loc).Resolve (rc);
3238 method = method.MakeGenericMethod (rc, targs);
3242 // Only base will allow this invocation to happen.
3244 if (method.IsAbstract) {
3245 rc.Report.SymbolRelatedToPreviousError (method);
3246 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3252 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3254 if (InstanceExpression == null)
3257 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3258 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3259 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3264 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3266 if (InstanceExpression == null)
3269 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3272 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3274 var ct = rc.CurrentType;
3275 if (ct == qualifier)
3278 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3281 qualifier = qualifier.GetDefinition ();
3282 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3289 public override bool ContainsEmitWithAwait ()
3291 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3294 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3297 type = type.GetDefinition ();
3299 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3302 type = type.DeclaringType;
3303 } while (type != null);
3308 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3310 if (InstanceExpression != null) {
3311 InstanceExpression = InstanceExpression.Resolve (rc);
3312 CheckProtectedMemberAccess (rc, member);
3315 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3316 UnsafeError (rc, loc);
3319 var dep = member.GetMissingDependencies ();
3321 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3324 if (!rc.IsObsolete) {
3325 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3327 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3330 if (!(member is FieldSpec))
3331 member.MemberDefinition.SetIsUsed ();
3334 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3336 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3339 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3341 rc.Report.SymbolRelatedToPreviousError (member);
3342 rc.Report.Error (1540, loc,
3343 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3344 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3347 public override void FlowAnalysis (FlowAnalysisContext fc)
3349 if (InstanceExpression != null)
3350 InstanceExpression.FlowAnalysis (fc);
3353 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3355 if (!ResolveInstanceExpressionCore (rc, rhs))
3359 // Check intermediate value modification which won't have any effect
3361 if (rhs != null && InstanceExpression.Type.IsStruct) {
3362 var fexpr = InstanceExpression as FieldExpr;
3363 if (fexpr != null) {
3364 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3367 if (fexpr.IsStatic) {
3368 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3369 fexpr.GetSignatureForError ());
3371 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3372 fexpr.GetSignatureForError ());
3378 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3379 if (rc.CurrentInitializerVariable != null) {
3380 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3381 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3383 rc.Report.Error (1612, loc,
3384 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3385 InstanceExpression.GetSignatureForError ());
3391 var lvr = InstanceExpression as LocalVariableReference;
3394 if (!lvr.local_info.IsReadonly)
3397 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3398 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3405 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3408 if (InstanceExpression != null) {
3409 if (InstanceExpression is TypeExpr) {
3410 var t = InstanceExpression.Type;
3412 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3413 if (oa != null && !rc.IsObsolete) {
3414 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3417 t = t.DeclaringType;
3418 } while (t != null);
3420 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3421 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3422 rc.Report.Error (176, loc,
3423 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3424 GetSignatureForError ());
3428 InstanceExpression = null;
3434 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3435 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3436 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3437 rc.Report.Error (236, loc,
3438 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3439 GetSignatureForError ());
3441 var fe = this as FieldExpr;
3442 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3443 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3444 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3446 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3450 rc.Report.Error (120, loc,
3451 "An object reference is required to access non-static member `{0}'",
3452 GetSignatureForError ());
3456 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3460 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3461 rc.Report.Error (38, loc,
3462 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3463 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3466 InstanceExpression = new This (loc).Resolve (rc);
3470 var me = InstanceExpression as MemberExpr;
3472 me.ResolveInstanceExpressionCore (rc, rhs);
3474 var fe = me as FieldExpr;
3475 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3476 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3477 rc.Report.Warning (1690, 1, loc,
3478 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3479 me.GetSignatureForError ());
3486 // Additional checks for l-value member access
3489 if (InstanceExpression is UnboxCast) {
3490 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3497 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3499 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3500 ec.Report.Warning (1720, 1, left.Location,
3501 "Expression will always cause a `{0}'", "System.NullReferenceException");
3504 InstanceExpression = left;
3508 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3510 TypeSpec instance_type = InstanceExpression.Type;
3511 if (TypeSpec.IsValueType (instance_type)) {
3512 if (InstanceExpression is IMemoryLocation) {
3513 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3515 // Cannot release the temporary variable when its address
3516 // is required to be on stack for any parent
3517 LocalTemporary t = new LocalTemporary (instance_type);
3518 InstanceExpression.Emit (ec);
3520 t.AddressOf (ec, AddressOp.Store);
3523 InstanceExpression.Emit (ec);
3525 // Only to make verifier happy
3526 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3527 ec.Emit (OpCodes.Box, instance_type);
3530 if (prepare_for_load)
3531 ec.Emit (OpCodes.Dup);
3534 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3537 public class ExtensionMethodCandidates
3539 readonly NamespaceContainer container;
3540 readonly IList<MethodSpec> methods;
3542 readonly IMemberContext context;
3544 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3546 this.context = context;
3547 this.methods = methods;
3548 this.container = nsContainer;
3549 this.index = lookupIndex;
3552 public NamespaceContainer Container {
3558 public IMemberContext Context {
3564 public int LookupIndex {
3570 public IList<MethodSpec> Methods {
3578 // Represents a group of extension method candidates for whole namespace
3580 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3582 ExtensionMethodCandidates candidates;
3583 public Expression ExtensionExpression;
3585 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3586 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3588 this.candidates = candidates;
3589 this.ExtensionExpression = extensionExpr;
3592 public override bool IsStatic {
3593 get { return true; }
3597 // For extension methodgroup we are not looking for base members but parent
3598 // namespace extension methods
3600 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3602 // TODO: candidates are null only when doing error reporting, that's
3603 // incorrect. We have to discover same extension methods in error mode
3604 if (candidates == null)
3607 int arity = type_arguments == null ? 0 : type_arguments.Count;
3609 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3610 if (candidates == null)
3613 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3616 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3618 // We are already here
3622 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3624 if (arguments == null)
3625 arguments = new Arguments (1);
3627 ExtensionExpression = ExtensionExpression.Resolve (ec);
3628 if (ExtensionExpression == null)
3631 var cand = candidates;
3632 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3633 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3635 // Restore candidates in case we are running in probing mode
3638 // Store resolved argument and restore original arguments
3640 // Clean-up modified arguments for error reporting
3641 arguments.RemoveAt (0);
3645 var me = ExtensionExpression as MemberExpr;
3647 me.ResolveInstanceExpression (ec, null);
3648 var fe = me as FieldExpr;
3650 fe.Spec.MemberDefinition.SetIsUsed ();
3653 InstanceExpression = null;
3657 #region IErrorHandler Members
3659 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3664 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3666 rc.Report.SymbolRelatedToPreviousError (best);
3667 rc.Report.Error (1928, loc,
3668 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3669 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3672 rc.Report.Error (1929, loc,
3673 "Extension method instance type `{0}' cannot be converted to `{1}'",
3674 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3680 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3685 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3694 /// MethodGroupExpr represents a group of method candidates which
3695 /// can be resolved to the best method overload
3697 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3699 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3701 protected IList<MemberSpec> Methods;
3702 MethodSpec best_candidate;
3703 TypeSpec best_candidate_return;
3704 protected TypeArguments type_arguments;
3706 SimpleName simple_name;
3707 protected TypeSpec queried_type;
3709 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3713 this.type = InternalType.MethodGroup;
3715 eclass = ExprClass.MethodGroup;
3716 queried_type = type;
3719 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3720 : this (new MemberSpec[] { m }, type, loc)
3726 public MethodSpec BestCandidate {
3728 return best_candidate;
3732 public TypeSpec BestCandidateReturnType {
3734 return best_candidate_return;
3738 public IList<MemberSpec> Candidates {
3744 protected override TypeSpec DeclaringType {
3746 return queried_type;
3750 public bool IsConditionallyExcluded {
3752 return Methods == Excluded;
3756 public override bool IsInstance {
3758 if (best_candidate != null)
3759 return !best_candidate.IsStatic;
3765 public override bool IsSideEffectFree {
3767 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3771 public override bool IsStatic {
3773 if (best_candidate != null)
3774 return best_candidate.IsStatic;
3780 public override string KindName {
3781 get { return "method"; }
3784 public override string Name {
3786 if (best_candidate != null)
3787 return best_candidate.Name;
3790 return Methods.First ().Name;
3797 // When best candidate is already know this factory can be used
3798 // to avoid expensive overload resolution to be called
3800 // NOTE: InstanceExpression has to be set manually
3802 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3804 return new MethodGroupExpr (best, queriedType, loc) {
3805 best_candidate = best,
3806 best_candidate_return = best.ReturnType
3810 public override string GetSignatureForError ()
3812 if (best_candidate != null)
3813 return best_candidate.GetSignatureForError ();
3815 return Methods.First ().GetSignatureForError ();
3818 public override Expression CreateExpressionTree (ResolveContext ec)
3820 if (best_candidate == null) {
3821 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3825 if (IsConditionallyExcluded)
3826 ec.Report.Error (765, loc,
3827 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3829 return new TypeOfMethod (best_candidate, loc);
3832 protected override Expression DoResolve (ResolveContext ec)
3834 this.eclass = ExprClass.MethodGroup;
3836 if (InstanceExpression != null) {
3837 InstanceExpression = InstanceExpression.Resolve (ec);
3838 if (InstanceExpression == null)
3845 public override void Emit (EmitContext ec)
3847 throw new NotSupportedException ();
3850 public void EmitCall (EmitContext ec, Arguments arguments)
3852 var call = new CallEmitter ();
3853 call.InstanceExpression = InstanceExpression;
3854 call.Emit (ec, best_candidate, arguments, loc);
3857 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3859 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3860 Name, target.GetSignatureForError ());
3863 public static bool IsExtensionMethodArgument (Expression expr)
3866 // LAMESPEC: No details about which expressions are not allowed
3868 return !(expr is TypeExpr) && !(expr is BaseThis);
3872 /// Find the Applicable Function Members (7.4.2.1)
3874 /// me: Method Group expression with the members to select.
3875 /// it might contain constructors or methods (or anything
3876 /// that maps to a method).
3878 /// Arguments: ArrayList containing resolved Argument objects.
3880 /// loc: The location if we want an error to be reported, or a Null
3881 /// location for "probing" purposes.
3883 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3884 /// that is the best match of me on Arguments.
3887 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3889 // TODO: causes issues with probing mode, remove explicit Kind check
3890 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3893 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3894 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3895 r.BaseMembersProvider = this;
3896 r.InstanceQualifier = this;
3899 if (cerrors != null)
3900 r.CustomErrors = cerrors;
3902 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3903 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3904 if (best_candidate == null)
3905 return r.BestCandidateIsDynamic ? this : null;
3907 // Overload resolver had to create a new method group, all checks bellow have already been executed
3908 if (r.BestCandidateNewMethodGroup != null)
3909 return r.BestCandidateNewMethodGroup;
3911 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3912 if (InstanceExpression != null) {
3913 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3914 InstanceExpression = null;
3916 if (best_candidate.IsStatic && simple_name != null) {
3917 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3920 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
3924 ResolveInstanceExpression (ec, null);
3927 var base_override = CandidateToBaseOverride (ec, best_candidate);
3928 if (base_override == best_candidate) {
3929 best_candidate_return = r.BestCandidateReturnType;
3931 best_candidate = base_override;
3932 best_candidate_return = best_candidate.ReturnType;
3935 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3936 ConstraintChecker cc = new ConstraintChecker (ec);
3937 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3941 // Additional check for possible imported base override method which
3942 // could not be done during IsOverrideMethodBaseTypeAccessible
3944 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3945 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3946 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3947 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3950 // Speed up the check by not doing it on disallowed targets
3951 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
3957 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3959 var fe = left as FieldExpr;
3962 // Using method-group on struct fields makes the struct assigned. I am not sure
3963 // why but that's what .net does
3965 fe.Spec.MemberDefinition.SetIsAssigned ();
3968 simple_name = original;
3969 return base.ResolveMemberAccess (ec, left, original);
3972 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3974 type_arguments = ta;
3977 #region IBaseMembersProvider Members
3979 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3981 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3984 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3986 if (queried_type == member.DeclaringType)
3989 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3990 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3994 // Extension methods lookup after ordinary methods candidates failed to apply
3996 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3998 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4001 if (!IsExtensionMethodArgument (InstanceExpression))
4004 int arity = type_arguments == null ? 0 : type_arguments.Count;
4005 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
4006 if (methods == null)
4009 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4010 emg.SetTypeArguments (rc, type_arguments);
4017 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4019 public ConstructorInstanceQualifier (TypeSpec type)
4022 InstanceType = type;
4025 public TypeSpec InstanceType { get; private set; }
4027 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4029 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4033 public struct OverloadResolver
4036 public enum Restrictions
4040 ProbingOnly = 1 << 1,
4041 CovariantDelegate = 1 << 2,
4042 NoBaseMembers = 1 << 3,
4043 BaseMembersIncluded = 1 << 4
4046 public interface IBaseMembersProvider
4048 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4049 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4050 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4053 public interface IErrorHandler
4055 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4056 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4057 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4058 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4061 public interface IInstanceQualifier
4063 TypeSpec InstanceType { get; }
4064 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4067 sealed class NoBaseMembers : IBaseMembersProvider
4069 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4071 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4076 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4081 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4087 struct AmbiguousCandidate
4089 public readonly MemberSpec Member;
4090 public readonly bool Expanded;
4091 public readonly AParametersCollection Parameters;
4093 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4096 Parameters = parameters;
4097 Expanded = expanded;
4102 IList<MemberSpec> members;
4103 TypeArguments type_arguments;
4104 IBaseMembersProvider base_provider;
4105 IErrorHandler custom_errors;
4106 IInstanceQualifier instance_qualifier;
4107 Restrictions restrictions;
4108 MethodGroupExpr best_candidate_extension_group;
4109 TypeSpec best_candidate_return_type;
4111 SessionReportPrinter lambda_conv_msgs;
4113 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4114 : this (members, null, restrictions, loc)
4118 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4121 if (members == null || members.Count == 0)
4122 throw new ArgumentException ("empty members set");
4124 this.members = members;
4126 type_arguments = targs;
4127 this.restrictions = restrictions;
4128 if (IsDelegateInvoke)
4129 this.restrictions |= Restrictions.NoBaseMembers;
4131 base_provider = NoBaseMembers.Instance;
4136 public IBaseMembersProvider BaseMembersProvider {
4138 return base_provider;
4141 base_provider = value;
4145 public bool BestCandidateIsDynamic { get; set; }
4148 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4150 public MethodGroupExpr BestCandidateNewMethodGroup {
4152 return best_candidate_extension_group;
4157 // Return type can be different between best candidate and closest override
4159 public TypeSpec BestCandidateReturnType {
4161 return best_candidate_return_type;
4165 public IErrorHandler CustomErrors {
4167 return custom_errors;
4170 custom_errors = value;
4174 TypeSpec DelegateType {
4176 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4177 throw new InternalErrorException ("Not running in delegate mode", loc);
4179 return members [0].DeclaringType;
4183 public IInstanceQualifier InstanceQualifier {
4185 return instance_qualifier;
4188 instance_qualifier = value;
4192 bool IsProbingOnly {
4194 return (restrictions & Restrictions.ProbingOnly) != 0;
4198 bool IsDelegateInvoke {
4200 return (restrictions & Restrictions.DelegateInvoke) != 0;
4207 // 7.4.3.3 Better conversion from expression
4208 // Returns : 1 if a->p is better,
4209 // 2 if a->q is better,
4210 // 0 if neither is better
4212 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4214 TypeSpec argument_type = a.Type;
4217 // If argument is an anonymous function
4219 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4221 // p and q are delegate types or expression tree types
4223 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4224 if (q.MemberDefinition != p.MemberDefinition) {
4229 // Uwrap delegate from Expression<T>
4231 q = TypeManager.GetTypeArguments (q)[0];
4232 p = TypeManager.GetTypeArguments (p)[0];
4235 var p_m = Delegate.GetInvokeMethod (p);
4236 var q_m = Delegate.GetInvokeMethod (q);
4239 // With identical parameter lists
4241 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4250 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4252 if (p.Kind == MemberKind.Void) {
4253 return q.Kind != MemberKind.Void ? 2 : 0;
4257 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4259 if (q.Kind == MemberKind.Void) {
4260 return p.Kind != MemberKind.Void ? 1: 0;
4263 var am = (AnonymousMethodExpression) a.Expr;
4266 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4267 // better conversion is performed between underlying types Y1 and Y2
4269 if (p.IsGenericTask || q.IsGenericTask) {
4270 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4271 q = q.TypeArguments[0];
4272 p = p.TypeArguments[0];
4274 } else if (q != p) {
4276 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
4278 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
4279 var am_rt = am.InferReturnType (ec, null, orig_q);
4280 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4282 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
4283 var am_rt = am.InferReturnType (ec, null, orig_p);
4284 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4290 // The parameters are identicial and return type is not void, use better type conversion
4291 // on return type to determine better one
4294 if (argument_type == p)
4297 if (argument_type == q)
4301 return BetterTypeConversion (ec, p, q);
4305 // 7.4.3.4 Better conversion from type
4307 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4309 if (p == null || q == null)
4310 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4312 switch (p.BuiltinType) {
4313 case BuiltinTypeSpec.Type.Int:
4314 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4317 case BuiltinTypeSpec.Type.Long:
4318 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4321 case BuiltinTypeSpec.Type.SByte:
4322 switch (q.BuiltinType) {
4323 case BuiltinTypeSpec.Type.Byte:
4324 case BuiltinTypeSpec.Type.UShort:
4325 case BuiltinTypeSpec.Type.UInt:
4326 case BuiltinTypeSpec.Type.ULong:
4330 case BuiltinTypeSpec.Type.Short:
4331 switch (q.BuiltinType) {
4332 case BuiltinTypeSpec.Type.UShort:
4333 case BuiltinTypeSpec.Type.UInt:
4334 case BuiltinTypeSpec.Type.ULong:
4338 case BuiltinTypeSpec.Type.Dynamic:
4339 // Dynamic is never better
4343 switch (q.BuiltinType) {
4344 case BuiltinTypeSpec.Type.Int:
4345 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4348 case BuiltinTypeSpec.Type.Long:
4349 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4352 case BuiltinTypeSpec.Type.SByte:
4353 switch (p.BuiltinType) {
4354 case BuiltinTypeSpec.Type.Byte:
4355 case BuiltinTypeSpec.Type.UShort:
4356 case BuiltinTypeSpec.Type.UInt:
4357 case BuiltinTypeSpec.Type.ULong:
4361 case BuiltinTypeSpec.Type.Short:
4362 switch (p.BuiltinType) {
4363 case BuiltinTypeSpec.Type.UShort:
4364 case BuiltinTypeSpec.Type.UInt:
4365 case BuiltinTypeSpec.Type.ULong:
4369 case BuiltinTypeSpec.Type.Dynamic:
4370 // Dynamic is never better
4374 // FIXME: handle lifted operators
4376 // TODO: this is expensive
4377 Expression p_tmp = new EmptyExpression (p);
4378 Expression q_tmp = new EmptyExpression (q);
4380 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4381 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4383 if (p_to_q && !q_to_p)
4386 if (q_to_p && !p_to_q)
4393 /// Determines "Better function" between candidate
4394 /// and the current best match
4397 /// Returns a boolean indicating :
4398 /// false if candidate ain't better
4399 /// true if candidate is better than the current best match
4401 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4402 MemberSpec best, AParametersCollection bparam, bool best_params)
4404 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4405 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4407 bool better_at_least_one = false;
4408 bool are_equivalent = true;
4409 int args_count = args == null ? 0 : args.Count;
4413 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4416 // Default arguments are ignored for better decision
4417 if (a.IsDefaultArgument)
4421 // When comparing named argument the parameter type index has to be looked up
4422 // in original parameter set (override version for virtual members)
4424 NamedArgument na = a as NamedArgument;
4426 int idx = cparam.GetParameterIndexByName (na.Name);
4427 ct = candidate_pd.Types[idx];
4428 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4429 ct = TypeManager.GetElementType (ct);
4431 idx = bparam.GetParameterIndexByName (na.Name);
4432 bt = best_pd.Types[idx];
4433 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4434 bt = TypeManager.GetElementType (bt);
4436 ct = candidate_pd.Types[c_idx];
4437 bt = best_pd.Types[b_idx];
4439 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4440 ct = TypeManager.GetElementType (ct);
4444 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4445 bt = TypeManager.GetElementType (bt);
4450 if (TypeSpecComparer.IsEqual (ct, bt))
4453 are_equivalent = false;
4454 int result = BetterExpressionConversion (ec, a, ct, bt);
4456 // for each argument, the conversion to 'ct' should be no worse than
4457 // the conversion to 'bt'.
4461 // for at least one argument, the conversion to 'ct' should be better than
4462 // the conversion to 'bt'.
4464 better_at_least_one = true;
4467 if (better_at_least_one)
4471 // Tie-breaking rules are applied only for equivalent parameter types
4473 if (!are_equivalent)
4477 // If candidate is applicable in its normal form and best has a params array and is applicable
4478 // only in its expanded form, then candidate is better
4480 if (candidate_params != best_params)
4481 return !candidate_params;
4484 // We have not reached end of parameters list due to params or used default parameters
4486 while (j < candidate_pd.Count && j < best_pd.Count) {
4487 var cand_param = candidate_pd.FixedParameters [j];
4488 var best_param = best_pd.FixedParameters [j];
4490 if (candidate_pd.Count == best_pd.Count) {
4494 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4495 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4497 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4498 return cand_param.HasDefaultValue;
4500 if (cand_param.HasDefaultValue) {
4506 // Neither is better when not all arguments are provided
4508 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4509 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4510 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4512 if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
4519 if (candidate_pd.Count != best_pd.Count)
4520 return candidate_pd.Count < best_pd.Count;
4523 // One is a non-generic method and second is a generic method, then non-generic is better
4525 if (best.IsGeneric != candidate.IsGeneric)
4526 return best.IsGeneric;
4529 // Both methods have the same number of parameters, and the parameters have equal types
4530 // Pick the "more specific" signature using rules over original (non-inflated) types
4532 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4533 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4535 bool specific_at_least_once = false;
4536 for (j = 0; j < args_count; ++j) {
4537 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4539 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4540 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4542 ct = candidate_def_pd.Types[j];
4543 bt = best_def_pd.Types[j];
4548 TypeSpec specific = MoreSpecific (ct, bt);
4552 specific_at_least_once = true;
4555 if (specific_at_least_once)
4561 static bool CheckInflatedArguments (MethodSpec ms)
4563 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4566 // Setup constraint checker for probing only
4567 ConstraintChecker cc = new ConstraintChecker (null);
4569 var mp = ms.Parameters.Types;
4570 for (int i = 0; i < mp.Length; ++i) {
4571 var type = mp[i] as InflatedTypeSpec;
4575 var targs = type.TypeArguments;
4576 if (targs.Length == 0)
4579 // TODO: Checking inflated MVAR arguments should be enough
4580 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4587 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4589 rc.Report.Error (1729, loc,
4590 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4591 type.GetSignatureForError (), argCount.ToString ());
4595 // Determines if the candidate method is applicable to the given set of arguments
4596 // There could be two different set of parameters for same candidate where one
4597 // is the closest override for default values and named arguments checks and second
4598 // one being the virtual base for the parameter types and modifiers.
4600 // A return value rates candidate method compatibility,
4601 // 0 = the best, int.MaxValue = the worst
4604 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)
4606 // Parameters of most-derived type used mainly for named and optional parameters
4607 var pd = pm.Parameters;
4609 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4610 // params modifier instead of most-derived type
4611 var cpd = ((IParametersMember) candidate).Parameters;
4612 int param_count = pd.Count;
4613 int optional_count = 0;
4615 Arguments orig_args = arguments;
4617 if (arg_count != param_count) {
4619 // No arguments expansion when doing exact match for delegates
4621 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4622 for (int i = 0; i < pd.Count; ++i) {
4623 if (pd.FixedParameters[i].HasDefaultValue) {
4624 optional_count = pd.Count - i;
4630 if (optional_count != 0) {
4631 // Readjust expected number when params used
4632 if (cpd.HasParams) {
4634 if (arg_count < param_count)
4636 } else if (arg_count > param_count) {
4637 int args_gap = System.Math.Abs (arg_count - param_count);
4638 return int.MaxValue - 10000 + args_gap;
4639 } else if (arg_count < param_count - optional_count) {
4640 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4641 return int.MaxValue - 10000 + args_gap;
4643 } else if (arg_count != param_count) {
4644 int args_gap = System.Math.Abs (arg_count - param_count);
4646 return int.MaxValue - 10000 + args_gap;
4647 if (arg_count < param_count - 1)
4648 return int.MaxValue - 10000 + args_gap;
4651 // Resize to fit optional arguments
4652 if (optional_count != 0) {
4653 if (arguments == null) {
4654 arguments = new Arguments (optional_count);
4656 // Have to create a new container, so the next run can do same
4657 var resized = new Arguments (param_count);
4658 resized.AddRange (arguments);
4659 arguments = resized;
4662 for (int i = arg_count; i < param_count; ++i)
4663 arguments.Add (null);
4667 if (arg_count > 0) {
4669 // Shuffle named arguments to the right positions if there are any
4671 if (arguments[arg_count - 1] is NamedArgument) {
4672 arg_count = arguments.Count;
4674 for (int i = 0; i < arg_count; ++i) {
4675 bool arg_moved = false;
4677 NamedArgument na = arguments[i] as NamedArgument;
4681 int index = pd.GetParameterIndexByName (na.Name);
4683 // Named parameter not found
4687 // already reordered
4692 if (index >= param_count) {
4693 // When using parameters which should not be available to the user
4694 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4697 arguments.Add (null);
4701 if (index == arg_count)
4704 temp = arguments [index];
4706 // The slot has been taken by positional argument
4707 if (temp != null && !(temp is NamedArgument))
4712 arguments = arguments.MarkOrderedArgument (na);
4716 if (arguments == orig_args) {
4717 arguments = new Arguments (orig_args.Count);
4718 arguments.AddRange (orig_args);
4721 arguments[index] = arguments[i];
4722 arguments[i] = temp;
4729 arg_count = arguments.Count;
4731 } else if (arguments != null) {
4732 arg_count = arguments.Count;
4736 // Don't do any expensive checks when the candidate cannot succeed
4738 if (arg_count != param_count && !cpd.HasParams)
4739 return (param_count - arg_count) * 2 + 1;
4741 var dep = candidate.GetMissingDependencies ();
4743 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4748 // 1. Handle generic method using type arguments when specified or type inference
4751 var ms = candidate as MethodSpec;
4752 if (ms != null && ms.IsGeneric) {
4753 if (type_arguments != null) {
4754 var g_args_count = ms.Arity;
4755 if (g_args_count != type_arguments.Count)
4756 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4758 if (type_arguments.Arguments != null)
4759 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4762 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4763 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4764 // candidate was found use the set to report more details about what was wrong with lambda body.
4765 // The general idea is to distinguish between code errors and errors caused by
4766 // trial-and-error type inference
4768 if (lambda_conv_msgs == null) {
4769 for (int i = 0; i < arg_count; i++) {
4770 Argument a = arguments[i];
4774 var am = a.Expr as AnonymousMethodExpression;
4776 if (lambda_conv_msgs == null)
4777 lambda_conv_msgs = new SessionReportPrinter ();
4779 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4784 var ti = new TypeInference (arguments);
4785 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4788 return ti.InferenceScore - 20000;
4791 // Clear any error messages when the result was success
4793 if (lambda_conv_msgs != null)
4794 lambda_conv_msgs.ClearSession ();
4796 if (i_args.Length != 0) {
4797 ms = ms.MakeGenericMethod (ec, i_args);
4802 // Type arguments constraints have to match for the method to be applicable
4804 if (!CheckInflatedArguments (ms)) {
4806 return int.MaxValue - 25000;
4810 // We have a generic return type and at same time the method is override which
4811 // means we have to also inflate override return type in case the candidate is
4812 // best candidate and override return type is different to base return type.
4814 // virtual Foo<T, object> with override Foo<T, dynamic>
4816 if (candidate != pm) {
4817 MethodSpec override_ms = (MethodSpec) pm;
4818 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4819 returnType = inflator.Inflate (returnType);
4821 returnType = ms.ReturnType;
4828 if (type_arguments != null)
4829 return int.MaxValue - 15000;
4835 // 2. Each argument has to be implicitly convertible to method parameter
4837 Parameter.Modifier p_mod = 0;
4840 for (int i = 0; i < arg_count; i++) {
4841 Argument a = arguments[i];
4843 var fp = pd.FixedParameters[i];
4844 if (!fp.HasDefaultValue) {
4845 arguments = orig_args;
4846 return arg_count * 2 + 2;
4850 // Get the default value expression, we can use the same expression
4851 // if the type matches
4853 Expression e = fp.DefaultValue;
4855 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4857 // Restore for possible error reporting
4858 for (int ii = i; ii < arg_count; ++ii)
4859 arguments.RemoveAt (i);
4861 return (arg_count - i) * 2 + 1;
4865 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4867 // LAMESPEC: Attributes can be mixed together with build-in priority
4869 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4870 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4871 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4872 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4873 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4874 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4878 arguments[i] = new Argument (e, Argument.AType.Default);
4882 if (p_mod != Parameter.Modifier.PARAMS) {
4883 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4885 } else if (!params_expanded_form) {
4886 params_expanded_form = true;
4887 pt = ((ElementTypeSpec) pt).Element;
4893 if (!params_expanded_form) {
4894 if (a.ArgType == Argument.AType.ExtensionType) {
4896 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4898 // LAMESPEC: or implicit type parameter conversion
4901 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4902 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4903 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4908 score = IsArgumentCompatible (ec, a, p_mod, pt);
4911 dynamicArgument = true;
4916 // It can be applicable in expanded form (when not doing exact match like for delegates)
4918 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4919 if (!params_expanded_form) {
4920 pt = ((ElementTypeSpec) pt).Element;
4924 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4927 params_expanded_form = true;
4928 dynamicArgument = true;
4929 } else if (score == 0 || arg_count > pd.Count) {
4930 params_expanded_form = true;
4935 if (params_expanded_form)
4937 return (arg_count - i) * 2 + score;
4942 // Restore original arguments for dynamic binder to keep the intention of original source code
4944 if (dynamicArgument)
4945 arguments = orig_args;
4950 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4952 if (e is Constant && e.Type == ptype)
4956 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4958 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4959 e = new MemberAccess (new MemberAccess (new MemberAccess (
4960 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4961 } else if (e is Constant) {
4963 // Handles int to int? conversions, DefaultParameterValue check
4965 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4969 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4972 return e.Resolve (ec);
4976 // Tests argument compatibility with the parameter
4977 // The possible return values are
4979 // 1 - modifier mismatch
4980 // 2 - type mismatch
4981 // -1 - dynamic binding required
4983 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4986 // Types have to be identical when ref or out modifer
4987 // is used and argument is not of dynamic type
4989 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4990 if (argument.Type != parameter) {
4992 // Do full equality check after quick path
4994 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4996 // Using dynamic for ref/out parameter can still succeed at runtime
4998 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5005 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5007 // Using dynamic for ref/out parameter can still succeed at runtime
5009 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5016 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5020 // Use implicit conversion in all modes to return same candidates when the expression
5021 // is used as argument or delegate conversion
5023 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5024 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5031 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5033 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5035 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5038 var ac_p = p as ArrayContainer;
5040 var ac_q = q as ArrayContainer;
5044 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5045 if (specific == ac_p.Element)
5047 if (specific == ac_q.Element)
5049 } else if (p.IsGeneric && q.IsGeneric) {
5050 var pargs = TypeManager.GetTypeArguments (p);
5051 var qargs = TypeManager.GetTypeArguments (q);
5053 bool p_specific_at_least_once = false;
5054 bool q_specific_at_least_once = false;
5056 for (int i = 0; i < pargs.Length; i++) {
5057 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5058 if (specific == pargs[i])
5059 p_specific_at_least_once = true;
5060 if (specific == qargs[i])
5061 q_specific_at_least_once = true;
5064 if (p_specific_at_least_once && !q_specific_at_least_once)
5066 if (!p_specific_at_least_once && q_specific_at_least_once)
5074 // Find the best method from candidate list
5076 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5078 List<AmbiguousCandidate> ambiguous_candidates = null;
5080 MemberSpec best_candidate;
5081 Arguments best_candidate_args = null;
5082 bool best_candidate_params = false;
5083 bool best_candidate_dynamic = false;
5084 int best_candidate_rate;
5085 IParametersMember best_parameter_member = null;
5087 int args_count = args != null ? args.Count : 0;
5089 Arguments candidate_args = args;
5090 bool error_mode = false;
5091 MemberSpec invocable_member = null;
5094 best_candidate = null;
5095 best_candidate_rate = int.MaxValue;
5097 var type_members = members;
5099 for (int i = 0; i < type_members.Count; ++i) {
5100 var member = type_members[i];
5103 // Methods in a base class are not candidates if any method in a derived
5104 // class is applicable
5106 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5110 if (!member.IsAccessible (rc))
5113 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5116 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5117 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5122 IParametersMember pm = member as IParametersMember;
5125 // Will use it later to report ambiguity between best method and invocable member
5127 if (Invocation.IsMemberInvocable (member))
5128 invocable_member = member;
5134 // Overload resolution is looking for base member but using parameter names
5135 // and default values from the closest member. That means to do expensive lookup
5136 // for the closest override for virtual or abstract members
5138 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5139 var override_params = base_provider.GetOverrideMemberParameters (member);
5140 if (override_params != null)
5141 pm = override_params;
5145 // Check if the member candidate is applicable
5147 bool params_expanded_form = false;
5148 bool dynamic_argument = false;
5149 TypeSpec rt = pm.MemberType;
5150 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
5152 if (lambda_conv_msgs != null)
5153 lambda_conv_msgs.EndSession ();
5156 // How does it score compare to others
5158 if (candidate_rate < best_candidate_rate) {
5160 // Fatal error (missing dependency), cannot continue
5161 if (candidate_rate < 0)
5164 best_candidate_rate = candidate_rate;
5165 best_candidate = member;
5166 best_candidate_args = candidate_args;
5167 best_candidate_params = params_expanded_form;
5168 best_candidate_dynamic = dynamic_argument;
5169 best_parameter_member = pm;
5170 best_candidate_return_type = rt;
5171 } else if (candidate_rate == 0) {
5173 // The member look is done per type for most operations but sometimes
5174 // it's not possible like for binary operators overload because they
5175 // are unioned between 2 sides
5177 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5178 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5183 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5185 // We pack all interface members into top level type which makes the overload resolution
5186 // more complicated for interfaces. We compensate it by removing methods with same
5187 // signature when building the cache hence this path should not really be hit often
5190 // interface IA { void Foo (int arg); }
5191 // interface IB : IA { void Foo (params int[] args); }
5193 // IB::Foo is the best overload when calling IB.Foo (1)
5196 if (ambiguous_candidates != null) {
5197 foreach (var amb_cand in ambiguous_candidates) {
5198 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5207 ambiguous_candidates = null;
5210 // Is the new candidate better
5211 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5215 best_candidate = member;
5216 best_candidate_args = candidate_args;
5217 best_candidate_params = params_expanded_form;
5218 best_candidate_dynamic = dynamic_argument;
5219 best_parameter_member = pm;
5220 best_candidate_return_type = rt;
5222 // It's not better but any other found later could be but we are not sure yet
5223 if (ambiguous_candidates == null)
5224 ambiguous_candidates = new List<AmbiguousCandidate> ();
5226 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5230 // Restore expanded arguments
5231 candidate_args = args;
5233 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5236 // We've found exact match
5238 if (best_candidate_rate == 0)
5242 // Try extension methods lookup when no ordinary method match was found and provider enables it
5245 var emg = base_provider.LookupExtensionMethod (rc);
5247 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5249 best_candidate_extension_group = emg;
5250 return (T) (MemberSpec) emg.BestCandidate;
5255 // Don't run expensive error reporting mode for probing
5262 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5265 lambda_conv_msgs = null;
5270 // No best member match found, report an error
5272 if (best_candidate_rate != 0 || error_mode) {
5273 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5277 if (best_candidate_dynamic) {
5278 if (args[0].ArgType == Argument.AType.ExtensionType) {
5279 rc.Report.Error (1973, loc,
5280 "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",
5281 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5285 // Check type constraints only when explicit type arguments are used
5287 if (best_candidate.IsGeneric && type_arguments != null) {
5288 MethodSpec bc = best_candidate as MethodSpec;
5289 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5290 ConstraintChecker cc = new ConstraintChecker (rc);
5291 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5295 BestCandidateIsDynamic = true;
5300 // These flags indicates we are running delegate probing conversion. No need to
5301 // do more expensive checks
5303 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5304 return (T) best_candidate;
5306 if (ambiguous_candidates != null) {
5308 // Now check that there are no ambiguities i.e the selected method
5309 // should be better than all the others
5311 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5312 var candidate = ambiguous_candidates [ix];
5314 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5315 var ambiguous = candidate.Member;
5316 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5317 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5318 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5319 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5320 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5323 return (T) best_candidate;
5328 if (invocable_member != null && !IsProbingOnly) {
5329 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5330 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5331 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5332 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5336 // And now check if the arguments are all
5337 // compatible, perform conversions if
5338 // necessary etc. and return if everything is
5341 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5344 if (best_candidate == null)
5348 // Don't run possibly expensive checks in probing mode
5350 if (!IsProbingOnly && !rc.IsInProbingMode) {
5352 // Check ObsoleteAttribute on the best method
5354 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5355 if (oa != null && !rc.IsObsolete)
5356 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5358 best_candidate.MemberDefinition.SetIsUsed ();
5361 args = best_candidate_args;
5362 return (T) best_candidate;
5365 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5367 return ResolveMember<MethodSpec> (rc, ref args);
5370 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5371 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5373 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5376 if (a.Type == InternalType.ErrorType)
5379 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5380 ec.Report.SymbolRelatedToPreviousError (method);
5381 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5382 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5383 TypeManager.CSharpSignature (method));
5386 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5387 TypeManager.CSharpSignature (method));
5388 } else if (IsDelegateInvoke) {
5389 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5390 DelegateType.GetSignatureForError ());
5392 ec.Report.SymbolRelatedToPreviousError (method);
5393 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5394 method.GetSignatureForError ());
5397 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5399 string index = (idx + 1).ToString ();
5400 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5401 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5402 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5403 index, Parameter.GetModifierSignature (a.Modifier));
5405 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5406 index, Parameter.GetModifierSignature (mod));
5408 string p1 = a.GetSignatureForError ();
5409 string p2 = paramType.GetSignatureForError ();
5412 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5413 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5416 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5417 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5418 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5421 ec.Report.Error (1503, a.Expr.Location,
5422 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5427 // We have failed to find exact match so we return error info about the closest match
5429 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5431 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5432 int arg_count = args == null ? 0 : args.Count;
5434 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5435 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5436 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5440 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5445 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5446 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5447 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5451 // For candidates which match on parameters count report more details about incorrect arguments
5454 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5455 // Reject any inaccessible member
5456 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5457 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5458 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5462 var ms = best_candidate as MethodSpec;
5463 if (ms != null && ms.IsGeneric) {
5464 bool constr_ok = true;
5465 if (ms.TypeArguments != null)
5466 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5468 if (ta_count == 0 && ms.TypeArguments == null) {
5469 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5473 rc.Report.Error (411, loc,
5474 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5475 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5482 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5488 // We failed to find any method with correct argument count, report best candidate
5490 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5493 if (best_candidate.Kind == MemberKind.Constructor) {
5494 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5495 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5496 } else if (IsDelegateInvoke) {
5497 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5498 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5499 DelegateType.GetSignatureForError (), arg_count.ToString ());
5501 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5502 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5503 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5504 name, arg_count.ToString ());
5508 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5510 var p = ((IParametersMember)best_candidate).Parameters;
5515 for (int i = p.Count - 1; i != 0; --i) {
5516 var fp = p.FixedParameters [i];
5517 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5524 foreach (var arg in args) {
5525 var na = arg as NamedArgument;
5529 if (na.Name == name) {
5538 return args.Count + 1 == pm.Parameters.Count;
5541 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5543 var pd = pm.Parameters;
5544 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5546 Parameter.Modifier p_mod = 0;
5548 int a_idx = 0, a_pos = 0;
5550 ArrayInitializer params_initializers = null;
5551 bool has_unsafe_arg = pm.MemberType.IsPointer;
5552 int arg_count = args == null ? 0 : args.Count;
5554 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5559 if (p_mod != Parameter.Modifier.PARAMS) {
5560 p_mod = pd.FixedParameters[a_idx].ModFlags;
5562 has_unsafe_arg |= pt.IsPointer;
5564 if (p_mod == Parameter.Modifier.PARAMS) {
5565 if (chose_params_expanded) {
5566 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5567 pt = TypeManager.GetElementType (pt);
5573 // Types have to be identical when ref or out modifer is used
5575 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5576 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5579 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5585 NamedArgument na = a as NamedArgument;
5587 int name_index = pd.GetParameterIndexByName (na.Name);
5588 if (name_index < 0 || name_index >= pd.Count) {
5589 if (IsDelegateInvoke) {
5590 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5591 ec.Report.Error (1746, na.Location,
5592 "The delegate `{0}' does not contain a parameter named `{1}'",
5593 DelegateType.GetSignatureForError (), na.Name);
5595 ec.Report.SymbolRelatedToPreviousError (member);
5596 ec.Report.Error (1739, na.Location,
5597 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5598 TypeManager.CSharpSignature (member), na.Name);
5600 } else if (args[name_index] != a && args[name_index] != null) {
5601 if (IsDelegateInvoke)
5602 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5604 ec.Report.SymbolRelatedToPreviousError (member);
5606 ec.Report.Error (1744, na.Location,
5607 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5612 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5615 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5616 custom_errors.NoArgumentMatch (ec, member);
5621 if (a.ArgType == Argument.AType.ExtensionType) {
5622 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5625 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5627 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5630 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5637 // Convert params arguments to an array initializer
5639 if (params_initializers != null) {
5640 // we choose to use 'a.Expr' rather than 'conv' so that
5641 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5642 params_initializers.Add (a.Expr);
5643 args.RemoveAt (a_idx--);
5649 // Update the argument with the implicit conversion
5653 if (a_idx != arg_count) {
5654 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5659 // Fill not provided arguments required by params modifier
5661 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5663 args = new Arguments (1);
5665 pt = ptypes[pd.Count - 1];
5666 pt = TypeManager.GetElementType (pt);
5667 has_unsafe_arg |= pt.IsPointer;
5668 params_initializers = new ArrayInitializer (0, loc);
5672 // Append an array argument with all params arguments
5674 if (params_initializers != null) {
5675 args.Add (new Argument (
5676 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5680 if (has_unsafe_arg && !ec.IsUnsafe) {
5681 Expression.UnsafeError (ec, loc);
5685 // We could infer inaccesible type arguments
5687 if (type_arguments == null && member.IsGeneric) {
5688 var ms = (MethodSpec) member;
5689 foreach (var ta in ms.TypeArguments) {
5690 if (!ta.IsAccessible (ec)) {
5691 ec.Report.SymbolRelatedToPreviousError (ta);
5692 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5702 public class ConstantExpr : MemberExpr
5704 readonly ConstSpec constant;
5706 public ConstantExpr (ConstSpec constant, Location loc)
5708 this.constant = constant;
5712 public override string Name {
5713 get { throw new NotImplementedException (); }
5716 public override string KindName {
5717 get { return "constant"; }
5720 public override bool IsInstance {
5721 get { return !IsStatic; }
5724 public override bool IsStatic {
5725 get { return true; }
5728 protected override TypeSpec DeclaringType {
5729 get { return constant.DeclaringType; }
5732 public override Expression CreateExpressionTree (ResolveContext ec)
5734 throw new NotSupportedException ("ET");
5737 protected override Expression DoResolve (ResolveContext rc)
5739 ResolveInstanceExpression (rc, null);
5740 DoBestMemberChecks (rc, constant);
5742 var c = constant.GetConstant (rc);
5744 // Creates reference expression to the constant value
5745 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5748 public override void Emit (EmitContext ec)
5750 throw new NotSupportedException ();
5753 public override string GetSignatureForError ()
5755 return constant.GetSignatureForError ();
5758 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5760 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5765 // Fully resolved expression that references a Field
5767 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5769 protected FieldSpec spec;
5770 VariableInfo variable_info;
5772 LocalTemporary temp;
5775 protected FieldExpr (Location l)
5780 public FieldExpr (FieldSpec spec, Location loc)
5785 type = spec.MemberType;
5788 public FieldExpr (FieldBase fi, Location l)
5795 public override string Name {
5801 public bool IsHoisted {
5803 IVariableReference hv = InstanceExpression as IVariableReference;
5804 return hv != null && hv.IsHoisted;
5808 public override bool IsInstance {
5810 return !spec.IsStatic;
5814 public override bool IsStatic {
5816 return spec.IsStatic;
5820 public override string KindName {
5821 get { return "field"; }
5824 public FieldSpec Spec {
5830 protected override TypeSpec DeclaringType {
5832 return spec.DeclaringType;
5836 public VariableInfo VariableInfo {
5838 return variable_info;
5844 public override string GetSignatureForError ()
5846 return spec.GetSignatureForError ();
5849 public bool IsMarshalByRefAccess (ResolveContext rc)
5851 // Checks possible ldflda of field access expression
5852 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5853 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5854 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5857 public void SetHasAddressTaken ()
5859 IVariableReference vr = InstanceExpression as IVariableReference;
5861 vr.SetHasAddressTaken ();
5865 protected override void CloneTo (CloneContext clonectx, Expression target)
5867 var t = (FieldExpr) target;
5869 if (InstanceExpression != null)
5870 t.InstanceExpression = InstanceExpression.Clone (clonectx);
5873 public override Expression CreateExpressionTree (ResolveContext ec)
5875 return CreateExpressionTree (ec, true);
5878 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5881 Expression instance;
5883 if (InstanceExpression == null) {
5884 instance = new NullLiteral (loc);
5885 } else if (convertInstance) {
5886 instance = InstanceExpression.CreateExpressionTree (ec);
5888 args = new Arguments (1);
5889 args.Add (new Argument (InstanceExpression));
5890 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5893 args = Arguments.CreateForExpressionTree (ec, null,
5895 CreateTypeOfExpression ());
5897 return CreateExpressionFactoryCall (ec, "Field", args);
5900 public Expression CreateTypeOfExpression ()
5902 return new TypeOfField (spec, loc);
5905 protected override Expression DoResolve (ResolveContext ec)
5907 spec.MemberDefinition.SetIsUsed ();
5909 return DoResolve (ec, null);
5912 Expression DoResolve (ResolveContext ec, Expression rhs)
5914 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5917 if (ResolveInstanceExpression (ec, rhs)) {
5918 // Resolve the field's instance expression while flow analysis is turned
5919 // off: when accessing a field "a.b", we must check whether the field
5920 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5922 if (lvalue_instance) {
5923 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5925 Expression right_side =
5926 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5928 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5930 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5933 if (InstanceExpression == null)
5937 DoBestMemberChecks (ec, spec);
5940 var fb = spec as FixedFieldSpec;
5941 IVariableReference var = InstanceExpression as IVariableReference;
5944 IFixedExpression fe = InstanceExpression as IFixedExpression;
5945 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5946 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5949 if (InstanceExpression.eclass != ExprClass.Variable) {
5950 ec.Report.SymbolRelatedToPreviousError (spec);
5951 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5952 TypeManager.GetFullNameSignature (spec));
5953 } else if (var != null && var.IsHoisted) {
5954 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5957 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5961 // Set flow-analysis variable info for struct member access. It will be check later
5962 // for precise error reporting
5964 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5965 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5968 eclass = ExprClass.Variable;
5972 public void SetFieldAssigned (FlowAnalysisContext fc)
5977 bool lvalue_instance = spec.DeclaringType.IsStruct;
5978 if (lvalue_instance) {
5979 var var = InstanceExpression as IVariableReference;
5980 if (var != null && var.VariableInfo != null) {
5981 fc.SetStructFieldAssigned (var.VariableInfo, Name);
5985 var fe = InstanceExpression as FieldExpr;
5987 Expression instance;
5990 instance = fe.InstanceExpression;
5991 var fe_instance = instance as FieldExpr;
5992 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
5993 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
5994 var var = InstanceExpression as IVariableReference;
5995 if (var != null && var.VariableInfo == null) {
5996 var var_inst = instance as IVariableReference;
5997 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
5998 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6002 if (fe_instance != null) {
6011 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6012 instance.FlowAnalysis (fc);
6014 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6015 InstanceExpression.FlowAnalysis (fc);
6019 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6021 // The return value is always null. Returning a value simplifies calling code.
6023 if (right_side == EmptyExpression.OutAccess) {
6025 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6026 GetSignatureForError ());
6028 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6029 GetSignatureForError ());
6035 if (right_side == EmptyExpression.LValueMemberAccess) {
6036 // Already reported as CS1648/CS1650
6040 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6042 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6043 GetSignatureForError ());
6045 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6046 GetSignatureForError ());
6052 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6053 GetSignatureForError ());
6055 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6056 GetSignatureForError ());
6062 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6064 if (spec is FixedFieldSpec) {
6065 // It could be much better error message but we want to be error compatible
6066 Error_ValueAssignment (ec, right_side);
6069 Expression e = DoResolve (ec, right_side);
6074 spec.MemberDefinition.SetIsAssigned ();
6076 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6077 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6078 ec.Report.Warning (420, 1, loc,
6079 "`{0}': A volatile field references will not be treated as volatile",
6080 spec.GetSignatureForError ());
6083 if (spec.IsReadOnly) {
6084 // InitOnly fields can only be assigned in constructors or initializers
6085 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6086 return Error_AssignToReadonly (ec, right_side);
6088 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6090 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6091 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6092 return Error_AssignToReadonly (ec, right_side);
6093 // static InitOnly fields cannot be assigned-to in an instance constructor
6094 if (IsStatic && !ec.IsStatic)
6095 return Error_AssignToReadonly (ec, right_side);
6096 // instance constructors can't modify InitOnly fields of other instances of the same type
6097 if (!IsStatic && !(InstanceExpression is This))
6098 return Error_AssignToReadonly (ec, right_side);
6102 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6103 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6104 ec.Report.Warning (197, 1, loc,
6105 "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",
6106 GetSignatureForError ());
6109 eclass = ExprClass.Variable;
6113 public override void FlowAnalysis (FlowAnalysisContext fc)
6115 var var = InstanceExpression as IVariableReference;
6117 var vi = var.VariableInfo;
6118 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6119 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6123 if (TypeSpec.IsValueType (InstanceExpression.Type))
6127 base.FlowAnalysis (fc);
6130 public override int GetHashCode ()
6132 return spec.GetHashCode ();
6135 public bool IsFixed {
6138 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6140 IVariableReference variable = InstanceExpression as IVariableReference;
6141 if (variable != null)
6142 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6144 IFixedExpression fe = InstanceExpression as IFixedExpression;
6145 return fe != null && fe.IsFixed;
6149 public override bool Equals (object obj)
6151 FieldExpr fe = obj as FieldExpr;
6155 if (spec != fe.spec)
6158 if (InstanceExpression == null || fe.InstanceExpression == null)
6161 return InstanceExpression.Equals (fe.InstanceExpression);
6164 public void Emit (EmitContext ec, bool leave_copy)
6166 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6170 ec.Emit (OpCodes.Volatile);
6172 ec.Emit (OpCodes.Ldsfld, spec);
6175 EmitInstance (ec, false);
6177 // Optimization for build-in types
6178 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6179 ec.EmitLoadFromPtr (type);
6181 var ff = spec as FixedFieldSpec;
6183 ec.Emit (OpCodes.Ldflda, spec);
6184 ec.Emit (OpCodes.Ldflda, ff.Element);
6187 ec.Emit (OpCodes.Volatile);
6189 ec.Emit (OpCodes.Ldfld, spec);
6195 ec.Emit (OpCodes.Dup);
6197 temp = new LocalTemporary (this.Type);
6203 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6205 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6206 if (isCompound && !(source is DynamicExpressionStatement)) {
6207 if (has_await_source) {
6209 InstanceExpression = InstanceExpression.EmitToField (ec);
6216 if (has_await_source)
6217 source = source.EmitToField (ec);
6219 EmitInstance (ec, prepared);
6225 ec.Emit (OpCodes.Dup);
6227 temp = new LocalTemporary (this.Type);
6232 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6233 ec.Emit (OpCodes.Volatile);
6235 spec.MemberDefinition.SetIsAssigned ();
6238 ec.Emit (OpCodes.Stsfld, spec);
6240 ec.Emit (OpCodes.Stfld, spec);
6250 // Emits store to field with prepared values on stack
6252 public void EmitAssignFromStack (EmitContext ec)
6255 ec.Emit (OpCodes.Stsfld, spec);
6257 ec.Emit (OpCodes.Stfld, spec);
6261 public override void Emit (EmitContext ec)
6266 public override void EmitSideEffect (EmitContext ec)
6268 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6270 if (is_volatile) // || is_marshal_by_ref ())
6271 base.EmitSideEffect (ec);
6274 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6276 if ((mode & AddressOp.Store) != 0)
6277 spec.MemberDefinition.SetIsAssigned ();
6278 if ((mode & AddressOp.Load) != 0)
6279 spec.MemberDefinition.SetIsUsed ();
6282 // Handle initonly fields specially: make a copy and then
6283 // get the address of the copy.
6286 if (spec.IsReadOnly){
6288 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6300 var temp = ec.GetTemporaryLocal (type);
6301 ec.Emit (OpCodes.Stloc, temp);
6302 ec.Emit (OpCodes.Ldloca, temp);
6308 ec.Emit (OpCodes.Ldsflda, spec);
6311 EmitInstance (ec, false);
6312 ec.Emit (OpCodes.Ldflda, spec);
6316 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6318 return MakeExpression (ctx);
6321 public override SLE.Expression MakeExpression (BuilderContext ctx)
6324 return base.MakeExpression (ctx);
6326 return SLE.Expression.Field (
6327 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6328 spec.GetMetaInfo ());
6332 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6334 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6340 // Expression that evaluates to a Property.
6342 // This is not an LValue because we need to re-write the expression. We
6343 // can not take data from the stack and store it.
6345 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6347 Arguments arguments;
6349 public PropertyExpr (PropertySpec spec, Location l)
6352 best_candidate = spec;
6353 type = spec.MemberType;
6358 protected override Arguments Arguments {
6367 protected override TypeSpec DeclaringType {
6369 return best_candidate.DeclaringType;
6373 public override string Name {
6375 return best_candidate.Name;
6379 public override bool IsInstance {
6385 public override bool IsStatic {
6387 return best_candidate.IsStatic;
6391 public override string KindName {
6392 get { return "property"; }
6395 public PropertySpec PropertyInfo {
6397 return best_candidate;
6403 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6405 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6408 var args_count = arguments == null ? 0 : arguments.Count;
6409 if (args_count != body.Parameters.Count && args_count == 0)
6412 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6413 mg.InstanceExpression = InstanceExpression;
6418 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6420 return new PropertyExpr (spec, loc) {
6426 public override Expression CreateExpressionTree (ResolveContext ec)
6429 if (IsSingleDimensionalArrayLength ()) {
6430 args = new Arguments (1);
6431 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6432 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6435 args = new Arguments (2);
6436 if (InstanceExpression == null)
6437 args.Add (new Argument (new NullLiteral (loc)));
6439 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6440 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6441 return CreateExpressionFactoryCall (ec, "Property", args);
6444 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6446 DoResolveLValue (rc, null);
6447 return new TypeOfMethod (Setter, loc);
6450 public override string GetSignatureForError ()
6452 return best_candidate.GetSignatureForError ();
6455 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6458 return base.MakeExpression (ctx);
6460 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6464 public override SLE.Expression MakeExpression (BuilderContext ctx)
6467 return base.MakeExpression (ctx);
6469 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6473 void Error_PropertyNotValid (ResolveContext ec)
6475 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6476 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6477 GetSignatureForError ());
6480 bool IsSingleDimensionalArrayLength ()
6482 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6485 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6486 return ac != null && ac.Rank == 1;
6489 public override void Emit (EmitContext ec, bool leave_copy)
6492 // Special case: length of single dimension array property is turned into ldlen
6494 if (IsSingleDimensionalArrayLength ()) {
6495 EmitInstance (ec, false);
6496 ec.Emit (OpCodes.Ldlen);
6497 ec.Emit (OpCodes.Conv_I4);
6501 base.Emit (ec, leave_copy);
6504 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6507 LocalTemporary await_source_arg = null;
6509 if (isCompound && !(source is DynamicExpressionStatement)) {
6510 emitting_compound_assignment = true;
6513 if (has_await_arguments) {
6514 await_source_arg = new LocalTemporary (Type);
6515 await_source_arg.Store (ec);
6517 args = new Arguments (1);
6518 args.Add (new Argument (await_source_arg));
6521 temp = await_source_arg;
6524 has_await_arguments = false;
6529 ec.Emit (OpCodes.Dup);
6530 temp = new LocalTemporary (this.Type);
6535 args = arguments ?? new Arguments (1);
6539 temp = new LocalTemporary (this.Type);
6541 args.Add (new Argument (temp));
6543 args.Add (new Argument (source));
6547 emitting_compound_assignment = false;
6549 var call = new CallEmitter ();
6550 call.InstanceExpression = InstanceExpression;
6552 call.InstanceExpressionOnStack = true;
6554 call.Emit (ec, Setter, args, loc);
6561 if (await_source_arg != null) {
6562 await_source_arg.Release (ec);
6566 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6568 eclass = ExprClass.PropertyAccess;
6570 if (best_candidate.IsNotCSharpCompatible) {
6571 Error_PropertyNotValid (rc);
6574 ResolveInstanceExpression (rc, right_side);
6576 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6577 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6578 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6580 type = p.MemberType;
6584 DoBestMemberChecks (rc, best_candidate);
6586 // Handling of com-imported properties with any number of default property parameters
6587 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6588 var p = best_candidate.Get.Parameters;
6589 arguments = new Arguments (p.Count);
6590 for (int i = 0; i < p.Count; ++i) {
6591 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6593 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6594 var p = best_candidate.Set.Parameters;
6595 arguments = new Arguments (p.Count - 1);
6596 for (int i = 0; i < p.Count - 1; ++i) {
6597 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6604 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6606 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6610 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6612 // getter and setter can be different for base calls
6613 MethodSpec getter, setter;
6614 protected T best_candidate;
6616 protected LocalTemporary temp;
6617 protected bool emitting_compound_assignment;
6618 protected bool has_await_arguments;
6620 protected PropertyOrIndexerExpr (Location l)
6627 protected abstract Arguments Arguments { get; set; }
6629 public MethodSpec Getter {
6638 public MethodSpec Setter {
6649 protected override Expression DoResolve (ResolveContext ec)
6651 if (eclass == ExprClass.Unresolved) {
6652 var expr = OverloadResolve (ec, null);
6657 return expr.Resolve (ec);
6660 if (!ResolveGetter (ec))
6666 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6668 if (right_side == EmptyExpression.OutAccess) {
6669 // TODO: best_candidate can be null at this point
6670 INamedBlockVariable variable = null;
6671 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6672 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6673 best_candidate.Name);
6675 right_side.DoResolveLValue (ec, this);
6680 if (eclass == ExprClass.Unresolved) {
6681 var expr = OverloadResolve (ec, right_side);
6686 return expr.ResolveLValue (ec, right_side);
6688 ResolveInstanceExpression (ec, right_side);
6691 if (!ResolveSetter (ec))
6698 // Implements the IAssignMethod interface for assignments
6700 public virtual void Emit (EmitContext ec, bool leave_copy)
6702 var call = new CallEmitter ();
6703 call.InstanceExpression = InstanceExpression;
6704 if (has_await_arguments)
6705 call.HasAwaitArguments = true;
6707 call.DuplicateArguments = emitting_compound_assignment;
6709 call.Emit (ec, Getter, Arguments, loc);
6711 if (call.HasAwaitArguments) {
6712 InstanceExpression = call.InstanceExpression;
6713 Arguments = call.EmittedArguments;
6714 has_await_arguments = true;
6718 ec.Emit (OpCodes.Dup);
6719 temp = new LocalTemporary (Type);
6724 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6726 public override void Emit (EmitContext ec)
6731 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6733 has_await_arguments = true;
6738 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6740 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6742 bool ResolveGetter (ResolveContext rc)
6744 if (!best_candidate.HasGet) {
6745 if (InstanceExpression != EmptyExpression.Null) {
6746 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6747 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6748 best_candidate.GetSignatureForError ());
6751 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
6752 if (best_candidate.HasDifferentAccessibility) {
6753 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6754 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6755 TypeManager.CSharpSignature (best_candidate));
6757 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6758 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6762 if (best_candidate.HasDifferentAccessibility) {
6763 CheckProtectedMemberAccess (rc, best_candidate.Get);
6766 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6770 bool ResolveSetter (ResolveContext rc)
6772 if (!best_candidate.HasSet) {
6773 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6774 GetSignatureForError ());
6778 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
6779 if (best_candidate.HasDifferentAccessibility) {
6780 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6781 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6782 GetSignatureForError ());
6784 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6785 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6789 if (best_candidate.HasDifferentAccessibility)
6790 CheckProtectedMemberAccess (rc, best_candidate.Set);
6792 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6798 /// Fully resolved expression that evaluates to an Event
6800 public class EventExpr : MemberExpr, IAssignMethod
6802 readonly EventSpec spec;
6805 public EventExpr (EventSpec spec, Location loc)
6813 protected override TypeSpec DeclaringType {
6815 return spec.DeclaringType;
6819 public override string Name {
6825 public override bool IsInstance {
6827 return !spec.IsStatic;
6831 public override bool IsStatic {
6833 return spec.IsStatic;
6837 public override string KindName {
6838 get { return "event"; }
6841 public MethodSpec Operator {
6849 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6852 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6854 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6855 if (spec.BackingField != null &&
6856 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6858 spec.MemberDefinition.SetIsUsed ();
6860 if (!ec.IsObsolete) {
6861 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6863 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6866 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6867 Error_AssignmentEventOnly (ec);
6869 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6871 InstanceExpression = null;
6873 return ml.ResolveMemberAccess (ec, left, original);
6877 return base.ResolveMemberAccess (ec, left, original);
6880 public override Expression CreateExpressionTree (ResolveContext ec)
6882 throw new NotSupportedException ("ET");
6885 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6887 if (right_side == EmptyExpression.EventAddition) {
6888 op = spec.AccessorAdd;
6889 } else if (right_side == EmptyExpression.EventSubtraction) {
6890 op = spec.AccessorRemove;
6894 Error_AssignmentEventOnly (ec);
6898 op = CandidateToBaseOverride (ec, op);
6902 protected override Expression DoResolve (ResolveContext ec)
6904 eclass = ExprClass.EventAccess;
6905 type = spec.MemberType;
6907 ResolveInstanceExpression (ec, null);
6909 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6910 Error_AssignmentEventOnly (ec);
6913 DoBestMemberChecks (ec, spec);
6917 public override void Emit (EmitContext ec)
6919 throw new NotSupportedException ();
6920 //Error_CannotAssign ();
6923 #region IAssignMethod Members
6925 public void Emit (EmitContext ec, bool leave_copy)
6927 throw new NotImplementedException ();
6930 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6932 if (leave_copy || !isCompound)
6933 throw new NotImplementedException ("EventExpr::EmitAssign");
6935 Arguments args = new Arguments (1);
6936 args.Add (new Argument (source));
6938 var call = new CallEmitter ();
6939 call.InstanceExpression = InstanceExpression;
6940 call.Emit (ec, op, args, loc);
6945 void Error_AssignmentEventOnly (ResolveContext ec)
6947 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6948 ec.Report.Error (79, loc,
6949 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6950 GetSignatureForError ());
6952 ec.Report.Error (70, loc,
6953 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6954 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6958 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6960 name = name.Substring (0, name.LastIndexOf ('.'));
6961 base.Error_CannotCallAbstractBase (rc, name);
6964 public override string GetSignatureForError ()
6966 return TypeManager.CSharpSignature (spec);
6969 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6971 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6975 public class TemporaryVariableReference : VariableReference
6977 public class Declarator : Statement
6979 TemporaryVariableReference variable;
6981 public Declarator (TemporaryVariableReference variable)
6983 this.variable = variable;
6987 protected override void DoEmit (EmitContext ec)
6989 variable.li.CreateBuilder (ec);
6992 public override void Emit (EmitContext ec)
6994 // Don't create sequence point
6998 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7003 protected override void CloneTo (CloneContext clonectx, Statement target)
7011 public TemporaryVariableReference (LocalVariable li, Location loc)
7014 this.type = li.Type;
7018 public override bool IsLockedByStatement {
7026 public LocalVariable LocalInfo {
7032 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
7034 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
7035 return new TemporaryVariableReference (li, loc);
7038 protected override Expression DoResolve (ResolveContext ec)
7040 eclass = ExprClass.Variable;
7043 // Don't capture temporary variables except when using
7044 // state machine redirection and block yields
7046 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7047 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7048 ec.IsVariableCapturingRequired) {
7049 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7050 storey.CaptureLocalVariable (ec, li);
7056 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7058 return Resolve (ec);
7061 public override void Emit (EmitContext ec)
7063 li.CreateBuilder (ec);
7068 public void EmitAssign (EmitContext ec, Expression source)
7070 li.CreateBuilder (ec);
7072 EmitAssign (ec, source, false, false);
7075 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7077 return li.HoistedVariant;
7080 public override bool IsFixed {
7081 get { return true; }
7084 public override bool IsRef {
7085 get { return false; }
7088 public override string Name {
7089 get { throw new NotImplementedException (); }
7092 public override void SetHasAddressTaken ()
7094 throw new NotImplementedException ();
7097 protected override ILocalVariable Variable {
7101 public override VariableInfo VariableInfo {
7102 get { return null; }
7107 /// Handles `var' contextual keyword; var becomes a keyword only
7108 /// if no type called var exists in a variable scope
7110 class VarExpr : SimpleName
7112 public VarExpr (Location loc)
7117 public bool InferType (ResolveContext ec, Expression right_side)
7120 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7122 type = right_side.Type;
7123 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7124 ec.Report.Error (815, loc,
7125 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7126 type.GetSignatureForError ());
7130 eclass = ExprClass.Variable;
7134 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7136 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7137 base.Error_TypeOrNamespaceNotFound (ec);
7139 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");