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, int arity, 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 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 ResolveFlags ExprClassToResolveFlags {
380 case ExprClass.Namespace:
381 return ResolveFlags.Type;
383 case ExprClass.MethodGroup:
384 return ResolveFlags.MethodGroup;
386 case ExprClass.TypeParameter:
387 return ResolveFlags.TypeParameter;
389 case ExprClass.Value:
390 case ExprClass.Variable:
391 case ExprClass.PropertyAccess:
392 case ExprClass.EventAccess:
393 case ExprClass.IndexerAccess:
394 return ResolveFlags.VariableOrValue;
397 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
403 // Implements identical simple name and type-name resolution
405 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
408 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
411 // 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
412 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
414 if (left is MemberExpr || left is VariableReference) {
415 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
416 if (identical_type != null && identical_type.Type == left.Type)
417 return identical_type;
423 public virtual string GetSignatureForError ()
425 return type.GetDefinition ().GetSignatureForError ();
429 /// Resolves an expression and performs semantic analysis on it.
433 /// Currently Resolve wraps DoResolve to perform sanity
434 /// checking and assertion checking on what we expect from Resolve.
436 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
438 if (eclass != ExprClass.Unresolved)
448 if ((flags & e.ExprClassToResolveFlags) == 0) {
449 e.Error_UnexpectedKind (ec, flags, loc);
454 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
457 } catch (Exception ex) {
458 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException)
461 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
462 return ErrorExpression.Instance; // TODO: Add location
467 /// Resolves an expression and performs semantic analysis on it.
469 public Expression Resolve (ResolveContext rc)
471 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
475 /// Resolves an expression for LValue assignment
479 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
480 /// checking and assertion checking on what we expect from Resolve
482 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
484 int errors = ec.Report.Errors;
485 bool out_access = right_side == EmptyExpression.OutAccess;
487 Expression e = DoResolveLValue (ec, right_side);
489 if (e != null && out_access && !(e is IMemoryLocation)) {
490 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
491 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
493 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
494 // e.GetType () + " " + e.GetSignatureForError ());
499 if (errors == ec.Report.Errors) {
500 Error_ValueAssignment (ec, right_side);
505 if (e.eclass == ExprClass.Unresolved)
506 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
508 if ((e.type == null) && !(e is GenericTypeExpr))
509 throw new Exception ("Expression " + e + " did not set its type after Resolve");
514 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
516 rc.Module.Compiler.Report.Error (182, loc,
517 "An attribute argument must be a constant expression, typeof expression or array creation expression");
521 /// Emits the code for the expression
525 /// The Emit method is invoked to generate the code
526 /// for the expression.
528 public abstract void Emit (EmitContext ec);
531 // Emit code to branch to @target if this expression is equivalent to @on_true.
532 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
533 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
534 // including the use of conditional branches. Note also that a branch MUST be emitted
535 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
538 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
541 // Emit this expression for its side effects, not for its value.
542 // The default implementation is to emit the value, and then throw it away.
543 // Subclasses can provide more efficient implementations, but those MUST be equivalent
544 public virtual void EmitSideEffect (EmitContext ec)
547 ec.Emit (OpCodes.Pop);
551 // Emits the expression into temporary field variable. The method
552 // should be used for await expressions only
554 public virtual Expression EmitToField (EmitContext ec)
557 // This is the await prepare Emit method. When emitting code like
558 // a + b we emit code like
564 // For await a + await b we have to interfere the flow to keep the
565 // stack clean because await yields from the expression. The emit
568 // a = a.EmitToField () // a is changed to temporary field access
569 // b = b.EmitToField ()
575 // The idea is to emit expression and leave the stack empty with
576 // result value still available.
578 // Expressions should override this default implementation when
579 // optimized version can be provided (e.g. FieldExpr)
582 // We can optimize for side-effect free expressions, they can be
583 // emitted out of order
585 if (IsSideEffectFree)
588 bool needs_temporary = ContainsEmitWithAwait ();
589 if (!needs_temporary)
592 // Emit original code
593 var field = EmitToFieldSource (ec);
596 // Store the result to temporary field when we
597 // cannot load `this' directly
599 field = ec.GetTemporaryField (type);
600 if (needs_temporary) {
602 // Create temporary local (we cannot load `this' before Emit)
604 var temp = ec.GetTemporaryLocal (type);
605 ec.Emit (OpCodes.Stloc, temp);
608 ec.Emit (OpCodes.Ldloc, temp);
609 field.EmitAssignFromStack (ec);
611 ec.FreeTemporaryLocal (temp, type);
613 field.EmitAssignFromStack (ec);
620 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
623 // Default implementation calls Emit method
629 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
631 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
632 bool contains_await = false;
634 for (int i = 1; i < expressions.Count; ++i) {
635 if (expressions[i].ContainsEmitWithAwait ()) {
636 contains_await = true;
641 if (contains_await) {
642 for (int i = 0; i < expressions.Count; ++i) {
643 expressions[i] = expressions[i].EmitToField (ec);
648 for (int i = 0; i < expressions.Count; ++i) {
649 expressions[i].Emit (ec);
654 /// Protected constructor. Only derivate types should
655 /// be able to be created
658 protected Expression ()
663 /// Returns a fully formed expression after a MemberLookup
666 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
668 if (spec is EventSpec)
669 return new EventExpr ((EventSpec) spec, loc);
670 if (spec is ConstSpec)
671 return new ConstantExpr ((ConstSpec) spec, loc);
672 if (spec is FieldSpec)
673 return new FieldExpr ((FieldSpec) spec, loc);
674 if (spec is PropertySpec)
675 return new PropertyExpr ((PropertySpec) spec, loc);
676 if (spec is TypeSpec)
677 return new TypeExpression (((TypeSpec) spec), loc);
682 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
684 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
686 rc.Report.SymbolRelatedToPreviousError (type);
688 // Report meaningful error for struct as they always have default ctor in C# context
689 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
691 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
692 type.GetSignatureForError ());
698 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
699 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
700 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
703 return r.ResolveMember<MethodSpec> (rc, ref args);
707 public enum MemberLookupRestrictions
716 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
717 // `qualifier_type' or null to lookup members in the current class.
719 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
721 var members = MemberCache.FindMembers (queried_type, name, false);
725 MemberSpec non_method = null;
726 MemberSpec ambig_non_method = null;
728 for (int i = 0; i < members.Count; ++i) {
729 var member = members[i];
731 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
732 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
735 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
738 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
742 if (!member.IsAccessible (rc))
746 // With runtime binder we can have a situation where queried type is inaccessible
747 // because it came via dynamic object, the check about inconsisted accessibility
748 // had no effect as the type was unknown during compilation
751 // private class N { }
753 // public dynamic Foo ()
759 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
763 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
764 if (member is MethodSpec)
765 return new MethodGroupExpr (members, queried_type, loc);
767 if (!Invocation.IsMemberInvocable (member))
771 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
773 } else if (!errorMode && !member.IsNotCSharpCompatible) {
775 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
776 // T has both an effective base class other than object and a non-empty effective interface set.
778 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
780 var tps = queried_type as TypeParameterSpec;
781 if (tps != null && tps.HasTypeConstraint) {
782 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
785 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
791 ambig_non_method = member;
795 if (non_method != null) {
796 if (ambig_non_method != null && rc != null) {
797 var report = rc.Module.Compiler.Report;
798 report.SymbolRelatedToPreviousError (non_method);
799 report.SymbolRelatedToPreviousError (ambig_non_method);
800 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
801 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
804 if (non_method is MethodSpec)
805 return new MethodGroupExpr (members, queried_type, loc);
807 return ExprClassFromMemberInfo (non_method, loc);
810 if (members[0].DeclaringType.BaseType == null)
813 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
815 } while (members != null);
820 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
822 throw new NotImplementedException ();
825 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
827 if (t == InternalType.ErrorType)
830 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
831 oper, t.GetSignatureForError ());
834 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
836 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
840 /// Returns an expression that can be used to invoke operator true
841 /// on the expression if it exists.
843 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
845 return GetOperatorTrueOrFalse (ec, e, true, loc);
849 /// Returns an expression that can be used to invoke operator false
850 /// on the expression if it exists.
852 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
854 return GetOperatorTrueOrFalse (ec, e, false, loc);
857 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
859 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
860 var methods = MemberCache.GetUserOperator (e.type, op, false);
864 Arguments arguments = new Arguments (1);
865 arguments.Add (new Argument (e));
867 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
868 var oper = res.ResolveOperator (ec, ref arguments);
873 return new UserOperatorCall (oper, arguments, null, loc);
876 public virtual string ExprClassName
880 case ExprClass.Unresolved:
882 case ExprClass.Value:
884 case ExprClass.Variable:
886 case ExprClass.Namespace:
890 case ExprClass.MethodGroup:
891 return "method group";
892 case ExprClass.PropertyAccess:
893 return "property access";
894 case ExprClass.EventAccess:
895 return "event access";
896 case ExprClass.IndexerAccess:
897 return "indexer access";
898 case ExprClass.Nothing:
900 case ExprClass.TypeParameter:
901 return "type parameter";
903 throw new Exception ("Should not happen");
908 /// Reports that we were expecting `expr' to be of class `expected'
910 public void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
912 var name = memberExpr.GetSignatureForError ();
914 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
917 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
919 string [] valid = new string [4];
922 if ((flags & ResolveFlags.VariableOrValue) != 0) {
923 valid [count++] = "variable";
924 valid [count++] = "value";
927 if ((flags & ResolveFlags.Type) != 0)
928 valid [count++] = "type";
930 if ((flags & ResolveFlags.MethodGroup) != 0)
931 valid [count++] = "method group";
934 valid [count++] = "unknown";
936 StringBuilder sb = new StringBuilder (valid [0]);
937 for (int i = 1; i < count - 1; i++) {
939 sb.Append (valid [i]);
942 sb.Append ("' or `");
943 sb.Append (valid [count - 1]);
946 ec.Report.Error (119, loc,
947 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
950 public static void UnsafeError (ResolveContext ec, Location loc)
952 UnsafeError (ec.Report, loc);
955 public static void UnsafeError (Report Report, Location loc)
957 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
961 // Converts `source' to an int, uint, long or ulong.
963 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
965 var btypes = ec.BuiltinTypes;
967 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
968 Arguments args = new Arguments (1);
969 args.Add (new Argument (source));
970 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
973 Expression converted;
975 using (ec.Set (ResolveContext.Options.CheckedScope)) {
976 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
977 if (converted == null)
978 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
979 if (converted == null)
980 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
981 if (converted == null)
982 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
984 if (converted == null) {
985 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
991 // Only positive constants are allowed at compile time
993 Constant c = converted as Constant;
994 if (c != null && c.IsNegative)
995 Error_NegativeArrayIndex (ec, source.loc);
997 // No conversion needed to array index
998 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1001 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1005 // Derived classes implement this method by cloning the fields that
1006 // could become altered during the Resolve stage
1008 // Only expressions that are created for the parser need to implement
1011 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1013 throw new NotImplementedException (
1015 "CloneTo not implemented for expression {0}", this.GetType ()));
1019 // Clones an expression created by the parser.
1021 // We only support expressions created by the parser so far, not
1022 // expressions that have been resolved (many more classes would need
1023 // to implement CloneTo).
1025 // This infrastructure is here merely for Lambda expressions which
1026 // compile the same code using different type values for the same
1027 // arguments to find the correct overload
1029 public virtual Expression Clone (CloneContext clonectx)
1031 Expression cloned = (Expression) MemberwiseClone ();
1032 CloneTo (clonectx, cloned);
1038 // Implementation of expression to expression tree conversion
1040 public abstract Expression CreateExpressionTree (ResolveContext ec);
1042 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1044 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1047 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1049 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1052 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1054 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1057 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1059 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1063 return new TypeExpression (t, loc);
1067 // Implemented by all expressions which support conversion from
1068 // compiler expression to invokable runtime expression. Used by
1069 // dynamic C# binder.
1071 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1073 throw new NotImplementedException ("MakeExpression for " + GetType ());
1076 public virtual object Accept (StructuralVisitor visitor)
1078 return visitor.Visit (this);
1083 /// This is just a base class for expressions that can
1084 /// appear on statements (invocations, object creation,
1085 /// assignments, post/pre increment and decrement). The idea
1086 /// being that they would support an extra Emition interface that
1087 /// does not leave a result on the stack.
1089 public abstract class ExpressionStatement : Expression
1091 public ExpressionStatement ResolveStatement (BlockContext ec)
1093 Expression e = Resolve (ec);
1097 ExpressionStatement es = e as ExpressionStatement;
1099 Error_InvalidExpressionStatement (ec);
1102 // This is quite expensive warning, try to limit the damage
1104 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1105 WarningAsyncWithoutWait (ec, e);
1111 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1113 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1114 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1119 // Need to do full resolve because GetAwaiter can be extension method
1120 // available only in this context
1122 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1126 var arguments = new Arguments (0);
1127 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1132 // Use same check rules as for real await
1134 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1135 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1138 bc.Report.Warning (4014, 1, e.Location,
1139 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1143 var inv = e as Invocation;
1144 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1145 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1146 bc.Report.Warning (4014, 1, e.Location,
1147 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1153 /// Requests the expression to be emitted in a `statement'
1154 /// context. This means that no new value is left on the
1155 /// stack after invoking this method (constrasted with
1156 /// Emit that will always leave a value on the stack).
1158 public abstract void EmitStatement (EmitContext ec);
1160 public override void EmitSideEffect (EmitContext ec)
1167 /// This kind of cast is used to encapsulate the child
1168 /// whose type is child.Type into an expression that is
1169 /// reported to return "return_type". This is used to encapsulate
1170 /// expressions which have compatible types, but need to be dealt
1171 /// at higher levels with.
1173 /// For example, a "byte" expression could be encapsulated in one
1174 /// of these as an "unsigned int". The type for the expression
1175 /// would be "unsigned int".
1178 public abstract class TypeCast : Expression
1180 protected readonly Expression child;
1182 protected TypeCast (Expression child, TypeSpec return_type)
1184 eclass = child.eclass;
1185 loc = child.Location;
1190 public Expression Child {
1196 public override bool ContainsEmitWithAwait ()
1198 return child.ContainsEmitWithAwait ();
1201 public override Expression CreateExpressionTree (ResolveContext ec)
1203 Arguments args = new Arguments (2);
1204 args.Add (new Argument (child.CreateExpressionTree (ec)));
1205 args.Add (new Argument (new TypeOf (type, loc)));
1207 if (type.IsPointer || child.Type.IsPointer)
1208 Error_PointerInsideExpressionTree (ec);
1210 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1213 protected override Expression DoResolve (ResolveContext ec)
1215 // This should never be invoked, we are born in fully
1216 // initialized state.
1221 public override void Emit (EmitContext ec)
1226 public override SLE.Expression MakeExpression (BuilderContext ctx)
1229 return base.MakeExpression (ctx);
1231 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1232 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1233 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1237 protected override void CloneTo (CloneContext clonectx, Expression t)
1242 public override bool IsNull {
1243 get { return child.IsNull; }
1247 public class EmptyCast : TypeCast {
1248 EmptyCast (Expression child, TypeSpec target_type)
1249 : base (child, target_type)
1253 public static Expression Create (Expression child, TypeSpec type)
1255 Constant c = child as Constant;
1257 return new EmptyConstantCast (c, type);
1259 EmptyCast e = child as EmptyCast;
1261 return new EmptyCast (e.child, type);
1263 return new EmptyCast (child, type);
1266 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1268 child.EmitBranchable (ec, label, on_true);
1271 public override void EmitSideEffect (EmitContext ec)
1273 child.EmitSideEffect (ec);
1278 // Used for predefined type user operator (no obsolete check, etc.)
1280 public class OperatorCast : TypeCast
1282 readonly MethodSpec conversion_operator;
1284 public OperatorCast (Expression expr, TypeSpec target_type)
1285 : this (expr, target_type, target_type, false)
1289 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1290 : this (expr, target_type, target_type, find_explicit)
1294 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1295 : base (expr, returnType)
1297 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1298 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1301 foreach (MethodSpec oper in mi) {
1302 if (oper.ReturnType != returnType)
1305 if (oper.Parameters.Types[0] == expr.Type) {
1306 conversion_operator = oper;
1312 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1313 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1316 public override void Emit (EmitContext ec)
1319 ec.Emit (OpCodes.Call, conversion_operator);
1324 // Constant specialization of EmptyCast.
1325 // We need to special case this since an empty cast of
1326 // a constant is still a constant.
1328 public class EmptyConstantCast : Constant
1330 public readonly Constant child;
1332 public EmptyConstantCast (Constant child, TypeSpec type)
1333 : base (child.Location)
1336 throw new ArgumentNullException ("child");
1339 this.eclass = child.eclass;
1343 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1345 if (child.Type == target_type)
1348 // FIXME: check that 'type' can be converted to 'target_type' first
1349 return child.ConvertExplicitly (in_checked_context, target_type);
1352 public override Expression CreateExpressionTree (ResolveContext ec)
1354 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1355 child.CreateExpressionTree (ec),
1356 new TypeOf (type, loc));
1359 Error_PointerInsideExpressionTree (ec);
1361 return CreateExpressionFactoryCall (ec, "Convert", args);
1364 public override bool IsDefaultValue {
1365 get { return child.IsDefaultValue; }
1368 public override bool IsNegative {
1369 get { return child.IsNegative; }
1372 public override bool IsNull {
1373 get { return child.IsNull; }
1376 public override bool IsOneInteger {
1377 get { return child.IsOneInteger; }
1380 public override bool IsSideEffectFree {
1382 return child.IsSideEffectFree;
1386 public override bool IsZeroInteger {
1387 get { return child.IsZeroInteger; }
1390 public override void Emit (EmitContext ec)
1395 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1397 child.EmitBranchable (ec, label, on_true);
1399 // Only to make verifier happy
1400 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1401 ec.Emit (OpCodes.Unbox_Any, type);
1404 public override void EmitSideEffect (EmitContext ec)
1406 child.EmitSideEffect (ec);
1409 public override object GetValue ()
1411 return child.GetValue ();
1414 public override string GetValueAsLiteral ()
1416 return child.GetValueAsLiteral ();
1419 public override long GetValueAsLong ()
1421 return child.GetValueAsLong ();
1424 public override Constant ConvertImplicitly (TypeSpec target_type)
1426 if (type == target_type)
1429 // FIXME: Do we need to check user conversions?
1430 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1433 return child.ConvertImplicitly (target_type);
1438 /// This class is used to wrap literals which belong inside Enums
1440 public class EnumConstant : Constant
1442 public Constant Child;
1444 public EnumConstant (Constant child, TypeSpec enum_type)
1445 : base (child.Location)
1449 this.eclass = ExprClass.Value;
1450 this.type = enum_type;
1453 protected EnumConstant (Location loc)
1458 public override void Emit (EmitContext ec)
1463 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1465 Child.EncodeAttributeValue (rc, enc, Child.Type);
1468 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1470 Child.EmitBranchable (ec, label, on_true);
1473 public override void EmitSideEffect (EmitContext ec)
1475 Child.EmitSideEffect (ec);
1478 public override string GetSignatureForError()
1480 return Type.GetSignatureForError ();
1483 public override object GetValue ()
1485 return Child.GetValue ();
1489 public override object GetTypedValue ()
1492 // The method can be used in dynamic context only (on closed types)
1494 // System.Enum.ToObject cannot be called on dynamic types
1495 // EnumBuilder has to be used, but we cannot use EnumBuilder
1496 // because it does not properly support generics
1498 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1502 public override string GetValueAsLiteral ()
1504 return Child.GetValueAsLiteral ();
1507 public override long GetValueAsLong ()
1509 return Child.GetValueAsLong ();
1512 public EnumConstant Increment()
1514 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1517 public override bool IsDefaultValue {
1519 return Child.IsDefaultValue;
1523 public override bool IsSideEffectFree {
1525 return Child.IsSideEffectFree;
1529 public override bool IsZeroInteger {
1530 get { return Child.IsZeroInteger; }
1533 public override bool IsNegative {
1535 return Child.IsNegative;
1539 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1541 if (Child.Type == target_type)
1544 return Child.ConvertExplicitly (in_checked_context, target_type);
1547 public override Constant ConvertImplicitly (TypeSpec type)
1549 if (this.type == type) {
1553 if (!Convert.ImplicitStandardConversionExists (this, type)){
1557 return Child.ConvertImplicitly (type);
1562 /// This kind of cast is used to encapsulate Value Types in objects.
1564 /// The effect of it is to box the value type emitted by the previous
1567 public class BoxedCast : TypeCast {
1569 public BoxedCast (Expression expr, TypeSpec target_type)
1570 : base (expr, target_type)
1572 eclass = ExprClass.Value;
1575 protected override Expression DoResolve (ResolveContext ec)
1577 // This should never be invoked, we are born in fully
1578 // initialized state.
1583 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1585 // Only boxing to object type is supported
1586 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1587 base.EncodeAttributeValue (rc, enc, targetType);
1591 enc.Encode (child.Type);
1592 child.EncodeAttributeValue (rc, enc, child.Type);
1595 public override void Emit (EmitContext ec)
1599 ec.Emit (OpCodes.Box, child.Type);
1602 public override void EmitSideEffect (EmitContext ec)
1604 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1605 // so, we need to emit the box+pop instructions in most cases
1606 if (child.Type.IsStruct &&
1607 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1608 child.EmitSideEffect (ec);
1610 base.EmitSideEffect (ec);
1614 public class UnboxCast : TypeCast {
1615 public UnboxCast (Expression expr, TypeSpec return_type)
1616 : base (expr, return_type)
1620 protected override Expression DoResolve (ResolveContext ec)
1622 // This should never be invoked, we are born in fully
1623 // initialized state.
1628 public override void Emit (EmitContext ec)
1632 ec.Emit (OpCodes.Unbox_Any, type);
1637 /// This is used to perform explicit numeric conversions.
1639 /// Explicit numeric conversions might trigger exceptions in a checked
1640 /// context, so they should generate the conv.ovf opcodes instead of
1643 public class ConvCast : TypeCast {
1644 public enum Mode : byte {
1645 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1647 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1648 U2_I1, U2_U1, U2_I2, U2_CH,
1649 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1650 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1651 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1652 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1653 CH_I1, CH_U1, CH_I2,
1654 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1655 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1661 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1662 : base (child, return_type)
1667 protected override Expression DoResolve (ResolveContext ec)
1669 // This should never be invoked, we are born in fully
1670 // initialized state.
1675 public override string ToString ()
1677 return String.Format ("ConvCast ({0}, {1})", mode, child);
1680 public override void Emit (EmitContext ec)
1684 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1686 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1687 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1688 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1689 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1690 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1692 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1693 case Mode.U1_CH: /* nothing */ break;
1695 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1696 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1697 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1698 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1699 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1700 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1702 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1703 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1704 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1705 case Mode.U2_CH: /* nothing */ break;
1707 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1708 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1709 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1710 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1711 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1712 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1713 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1715 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1716 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1717 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1718 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1719 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1720 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1722 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1723 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1724 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1725 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1726 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1727 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1728 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1729 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1730 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1732 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1733 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1734 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1735 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1736 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1737 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1738 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1739 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1740 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1742 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1743 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1744 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1746 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1747 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1748 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1749 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1750 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1751 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1752 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1753 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1754 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1756 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1757 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1758 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1759 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1760 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1761 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1762 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1763 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1764 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1765 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1767 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1771 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1772 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1773 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1774 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1775 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1777 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1778 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1780 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1781 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1782 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1783 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1784 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1785 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1787 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1788 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1789 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1790 case Mode.U2_CH: /* nothing */ break;
1792 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1793 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1794 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1795 case Mode.I4_U4: /* nothing */ break;
1796 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1797 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1798 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1800 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1801 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1802 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1803 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1804 case Mode.U4_I4: /* nothing */ break;
1805 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1807 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1808 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1809 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1810 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1811 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1812 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1813 case Mode.I8_U8: /* nothing */ break;
1814 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1815 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1817 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1818 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1819 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1820 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1821 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1822 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1823 case Mode.U8_I8: /* nothing */ break;
1824 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1825 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1827 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1828 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1829 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1831 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1832 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1833 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1834 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1835 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1836 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1837 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1838 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1839 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1841 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1842 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1843 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1844 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1845 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1846 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1847 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1848 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1849 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1850 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1852 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1858 class OpcodeCast : TypeCast
1862 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1863 : base (child, return_type)
1868 protected override Expression DoResolve (ResolveContext ec)
1870 // This should never be invoked, we are born in fully
1871 // initialized state.
1876 public override void Emit (EmitContext ec)
1882 public TypeSpec UnderlyingType {
1883 get { return child.Type; }
1888 // Opcode casts expression with 2 opcodes but only
1889 // single expression tree node
1891 class OpcodeCastDuplex : OpcodeCast
1893 readonly OpCode second;
1895 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1896 : base (child, returnType, first)
1898 this.second = second;
1901 public override void Emit (EmitContext ec)
1909 /// This kind of cast is used to encapsulate a child and cast it
1910 /// to the class requested
1912 public sealed class ClassCast : TypeCast {
1913 readonly bool forced;
1915 public ClassCast (Expression child, TypeSpec return_type)
1916 : base (child, return_type)
1920 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1921 : base (child, return_type)
1923 this.forced = forced;
1926 public override void Emit (EmitContext ec)
1930 bool gen = TypeManager.IsGenericParameter (child.Type);
1932 ec.Emit (OpCodes.Box, child.Type);
1934 if (type.IsGenericParameter) {
1935 ec.Emit (OpCodes.Unbox_Any, type);
1942 ec.Emit (OpCodes.Castclass, type);
1947 // Created during resolving pahse when an expression is wrapped or constantified
1948 // and original expression can be used later (e.g. for expression trees)
1950 public class ReducedExpression : Expression
1952 sealed class ReducedConstantExpression : EmptyConstantCast
1954 readonly Expression orig_expr;
1956 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1957 : base (expr, expr.Type)
1959 this.orig_expr = orig_expr;
1962 public override Constant ConvertImplicitly (TypeSpec target_type)
1964 Constant c = base.ConvertImplicitly (target_type);
1966 c = new ReducedConstantExpression (c, orig_expr);
1971 public override Expression CreateExpressionTree (ResolveContext ec)
1973 return orig_expr.CreateExpressionTree (ec);
1976 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1978 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1980 c = new ReducedConstantExpression (c, orig_expr);
1984 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1987 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
1989 if (orig_expr is Conditional)
1990 child.EncodeAttributeValue (rc, enc, targetType);
1992 base.EncodeAttributeValue (rc, enc, targetType);
1996 sealed class ReducedExpressionStatement : ExpressionStatement
1998 readonly Expression orig_expr;
1999 readonly ExpressionStatement stm;
2001 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2003 this.orig_expr = orig;
2005 this.eclass = stm.eclass;
2006 this.type = stm.Type;
2008 this.loc = orig.Location;
2011 public override bool ContainsEmitWithAwait ()
2013 return stm.ContainsEmitWithAwait ();
2016 public override Expression CreateExpressionTree (ResolveContext ec)
2018 return orig_expr.CreateExpressionTree (ec);
2021 protected override Expression DoResolve (ResolveContext ec)
2026 public override void Emit (EmitContext ec)
2031 public override void EmitStatement (EmitContext ec)
2033 stm.EmitStatement (ec);
2037 readonly Expression expr, orig_expr;
2039 private ReducedExpression (Expression expr, Expression orig_expr)
2042 this.eclass = expr.eclass;
2043 this.type = expr.Type;
2044 this.orig_expr = orig_expr;
2045 this.loc = orig_expr.Location;
2050 public override bool IsSideEffectFree {
2052 return expr.IsSideEffectFree;
2056 public Expression OriginalExpression {
2064 public override bool ContainsEmitWithAwait ()
2066 return expr.ContainsEmitWithAwait ();
2070 // Creates fully resolved expression switcher
2072 public static Constant Create (Constant expr, Expression original_expr)
2074 if (expr.eclass == ExprClass.Unresolved)
2075 throw new ArgumentException ("Unresolved expression");
2077 return new ReducedConstantExpression (expr, original_expr);
2080 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2082 return new ReducedExpressionStatement (s, orig);
2085 public static Expression Create (Expression expr, Expression original_expr)
2087 return Create (expr, original_expr, true);
2091 // Creates unresolved reduce expression. The original expression has to be
2092 // already resolved. Created expression is constant based based on `expr'
2093 // value unless canBeConstant is used
2095 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2097 if (canBeConstant) {
2098 Constant c = expr as Constant;
2100 return Create (c, original_expr);
2103 ExpressionStatement s = expr as ExpressionStatement;
2105 return Create (s, original_expr);
2107 if (expr.eclass == ExprClass.Unresolved)
2108 throw new ArgumentException ("Unresolved expression");
2110 return new ReducedExpression (expr, original_expr);
2113 public override Expression CreateExpressionTree (ResolveContext ec)
2115 return orig_expr.CreateExpressionTree (ec);
2118 protected override Expression DoResolve (ResolveContext ec)
2123 public override void Emit (EmitContext ec)
2128 public override Expression EmitToField (EmitContext ec)
2130 return expr.EmitToField(ec);
2133 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2135 expr.EmitBranchable (ec, target, on_true);
2138 public override SLE.Expression MakeExpression (BuilderContext ctx)
2140 return orig_expr.MakeExpression (ctx);
2145 // Standard composite pattern
2147 public abstract class CompositeExpression : Expression
2149 protected Expression expr;
2151 protected CompositeExpression (Expression expr)
2154 this.loc = expr.Location;
2157 public override bool ContainsEmitWithAwait ()
2159 return expr.ContainsEmitWithAwait ();
2162 public override Expression CreateExpressionTree (ResolveContext rc)
2164 return expr.CreateExpressionTree (rc);
2167 public Expression Child {
2168 get { return expr; }
2171 protected override Expression DoResolve (ResolveContext rc)
2173 expr = expr.Resolve (rc);
2176 eclass = expr.eclass;
2182 public override void Emit (EmitContext ec)
2187 public override bool IsNull {
2188 get { return expr.IsNull; }
2193 // Base of expressions used only to narrow resolve flow
2195 public abstract class ShimExpression : Expression
2197 protected Expression expr;
2199 protected ShimExpression (Expression expr)
2204 public Expression Expr {
2210 protected override void CloneTo (CloneContext clonectx, Expression t)
2215 ShimExpression target = (ShimExpression) t;
2216 target.expr = expr.Clone (clonectx);
2219 public override bool ContainsEmitWithAwait ()
2221 return expr.ContainsEmitWithAwait ();
2224 public override Expression CreateExpressionTree (ResolveContext ec)
2226 throw new NotSupportedException ("ET");
2229 public override void Emit (EmitContext ec)
2231 throw new InternalErrorException ("Missing Resolve call");
2237 // Unresolved type name expressions
2239 public abstract class ATypeNameExpression : FullNamedExpression
2242 protected TypeArguments targs;
2244 protected ATypeNameExpression (string name, Location l)
2250 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2257 protected ATypeNameExpression (string name, int arity, Location l)
2258 : this (name, new UnboundTypeArguments (arity), l)
2264 protected int Arity {
2266 return targs == null ? 0 : targs.Count;
2270 public bool HasTypeArguments {
2272 return targs != null && !targs.IsEmpty;
2276 public string Name {
2285 public TypeArguments TypeArguments {
2293 public override bool Equals (object obj)
2295 ATypeNameExpression atne = obj as ATypeNameExpression;
2296 return atne != null && atne.Name == Name &&
2297 (targs == null || targs.Equals (atne.targs));
2300 public override int GetHashCode ()
2302 return Name.GetHashCode ();
2305 // TODO: Move it to MemberCore
2306 public static string GetMemberType (MemberCore mc)
2312 if (mc is FieldBase)
2314 if (mc is MethodCore)
2316 if (mc is EnumMember)
2324 public override string GetSignatureForError ()
2326 if (targs != null) {
2327 return Name + "<" + targs.GetSignatureForError () + ">";
2333 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2337 /// SimpleName expressions are formed of a single word and only happen at the beginning
2338 /// of a dotted-name.
2340 public class SimpleName : ATypeNameExpression
2342 public SimpleName (string name, Location l)
2347 public SimpleName (string name, TypeArguments args, Location l)
2348 : base (name, args, l)
2352 public SimpleName (string name, int arity, Location l)
2353 : base (name, arity, l)
2357 public SimpleName GetMethodGroup ()
2359 return new SimpleName (Name, targs, loc);
2362 protected override Expression DoResolve (ResolveContext rc)
2364 var e = SimpleNameResolve (rc, null, false);
2366 var fe = e as FieldExpr;
2368 fe.VerifyAssignedStructField (rc, null);
2374 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2376 return SimpleNameResolve (ec, right_side, false);
2379 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2381 if (ctx.CurrentType != null) {
2382 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2383 if (member != null) {
2384 member.Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2389 var report = ctx.Module.Compiler.Report;
2391 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2392 if (retval != null) {
2393 report.SymbolRelatedToPreviousError (retval.Type);
2394 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2398 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2399 if (retval != null) {
2400 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2404 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2405 if (ns_candidates != null) {
2406 if (ctx is UsingAliasNamespace.AliasContext) {
2407 report.Error (246, loc,
2408 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2409 ns_candidates[0], Name);
2411 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2412 report.Error (246, loc,
2413 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2417 report.Error (246, loc,
2418 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2423 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2425 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2428 if (fne.Type != null && Arity > 0) {
2429 if (HasTypeArguments) {
2430 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2431 if (ct.ResolveAsType (ec) == null)
2437 return new GenericOpenTypeExpr (fne.Type, loc);
2441 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2443 if (!(fne is Namespace))
2447 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2448 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2449 ec.Module.Compiler.Report.Error (1980, Location,
2450 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2451 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2454 fne = new DynamicTypeExpr (loc);
2455 fne.ResolveAsType (ec);
2461 Error_TypeOrNamespaceNotFound (ec);
2465 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2467 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2470 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2472 int lookup_arity = Arity;
2473 bool errorMode = false;
2475 Block current_block = rc.CurrentBlock;
2476 INamedBlockVariable variable = null;
2477 bool variable_found = false;
2481 // Stage 1: binding to local variables or parameters
2483 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2485 if (current_block != null && lookup_arity == 0) {
2486 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2487 if (!variable.IsDeclared) {
2488 // We found local name in accessible block but it's not
2489 // initialized yet, maybe the user wanted to bind to something else
2491 variable_found = true;
2493 e = variable.CreateReferenceExpression (rc, loc);
2496 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2505 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2507 TypeSpec member_type = rc.CurrentType;
2508 for (; member_type != null; member_type = member_type.DeclaringType) {
2509 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2513 var me = e as MemberExpr;
2515 // The name matches a type, defer to ResolveAsTypeStep
2523 if (variable != null) {
2524 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2525 rc.Report.Error (844, loc,
2526 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2527 Name, me.GetSignatureForError ());
2531 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2532 // Leave it to overload resolution to report correct error
2534 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2535 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2538 // LAMESPEC: again, ignores InvocableOnly
2539 if (variable != null) {
2540 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2541 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2545 // MemberLookup does not check accessors availability, this is actually needed for properties only
2547 var pe = me as PropertyExpr;
2550 // Break as there is no other overload available anyway
2551 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2552 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2555 pe.Getter = pe.PropertyInfo.Get;
2557 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2560 pe.Setter = pe.PropertyInfo.Set;
2565 // TODO: It's used by EventExpr -> FieldExpr transformation only
2566 // TODO: Should go to MemberAccess
2567 me = me.ResolveMemberAccess (rc, null, null);
2571 me.SetTypeArguments (rc, targs);
2578 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2580 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2581 if (IsPossibleTypeOrNamespace (rc)) {
2582 if (variable != null) {
2583 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2584 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2587 return ResolveAsTypeOrNamespace (rc);
2592 if (variable_found) {
2593 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2596 var tparams = rc.CurrentTypeParameters;
2597 if (tparams != null) {
2598 if (tparams.Find (Name) != null) {
2599 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2604 var ct = rc.CurrentType;
2606 if (ct.MemberDefinition.TypeParametersCount > 0) {
2607 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2608 if (ctp.Name == Name) {
2609 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2615 ct = ct.DeclaringType;
2616 } while (ct != null);
2619 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2620 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2622 rc.Report.SymbolRelatedToPreviousError (e.Type);
2623 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2627 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2629 me.Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2630 return ErrorExpression.Instance;
2634 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2636 if (e.Type.Arity != Arity) {
2637 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2641 if (e is TypeExpr) {
2642 e.Error_UnexpectedKind (rc, e, "variable", e.ExprClassName, loc);
2647 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2650 return ErrorExpression.Instance;
2653 if (rc.Module.Evaluator != null) {
2654 var fi = rc.Module.Evaluator.LookupField (Name);
2656 return new FieldExpr (fi.Item1, loc);
2664 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2666 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2671 if (right_side != null) {
2672 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2673 e.Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2677 e = e.ResolveLValue (ec, right_side);
2685 public override object Accept (StructuralVisitor visitor)
2687 return visitor.Visit (this);
2692 /// Represents a namespace or a type. The name of the class was inspired by
2693 /// section 10.8.1 (Fully Qualified Names).
2695 public abstract class FullNamedExpression : Expression
2697 protected override void CloneTo (CloneContext clonectx, Expression target)
2699 // Do nothing, most unresolved type expressions cannot be
2700 // resolved to different type
2703 public override bool ContainsEmitWithAwait ()
2708 public override Expression CreateExpressionTree (ResolveContext ec)
2710 throw new NotSupportedException ("ET");
2713 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2716 // This is used to resolve the expression as a type, a null
2717 // value will be returned if the expression is not a type
2720 public override TypeSpec ResolveAsType (IMemberContext mc)
2722 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2727 TypeExpr te = fne as TypeExpr;
2729 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2737 var dep = type.GetMissingDependencies ();
2739 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2742 if (type.Kind == MemberKind.Void) {
2743 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2747 // Obsolete checks cannot be done when resolving base context as they
2748 // require type dependencies to be set but we are in process of resolving them
2750 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2751 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2752 if (obsolete_attr != null && !mc.IsObsolete) {
2753 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2761 public override void Emit (EmitContext ec)
2763 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2764 GetSignatureForError ());
2769 /// Expression that evaluates to a type
2771 public abstract class TypeExpr : FullNamedExpression
2773 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2779 protected sealed override Expression DoResolve (ResolveContext ec)
2785 public override bool Equals (object obj)
2787 TypeExpr tobj = obj as TypeExpr;
2791 return Type == tobj.Type;
2794 public override int GetHashCode ()
2796 return Type.GetHashCode ();
2801 /// Fully resolved Expression that already evaluated to a type
2803 public class TypeExpression : TypeExpr
2805 public TypeExpression (TypeSpec t, Location l)
2808 eclass = ExprClass.Type;
2812 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2819 /// This class denotes an expression which evaluates to a member
2820 /// of a struct or a class.
2822 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2825 // An instance expression associated with this member, if it's a
2826 // non-static member
2828 public Expression InstanceExpression;
2831 /// The name of this member.
2833 public abstract string Name {
2838 // When base.member is used
2840 public bool IsBase {
2841 get { return InstanceExpression is BaseThis; }
2845 /// Whether this is an instance member.
2847 public abstract bool IsInstance {
2852 /// Whether this is a static member.
2854 public abstract bool IsStatic {
2858 public abstract string KindName {
2862 protected abstract TypeSpec DeclaringType {
2866 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2868 return InstanceExpression.Type;
2873 // Converts best base candidate for virtual method starting from QueriedBaseType
2875 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2878 // Only when base.member is used and method is virtual
2884 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2885 // means for base.member access we have to find the closest match after we found best candidate
2887 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2889 // The method could already be what we are looking for
2891 TypeSpec[] targs = null;
2892 if (method.DeclaringType != InstanceExpression.Type) {
2893 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
2894 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2895 if (base_override.IsGeneric)
2896 targs = method.TypeArguments;
2898 method = base_override;
2903 // When base access is used inside anonymous method/iterator/etc we need to
2904 // get back to the context of original type. We do it by emiting proxy
2905 // method in original class and rewriting base call to this compiler
2906 // generated method call which does the actual base invocation. This may
2907 // introduce redundant storey but with `this' only but it's tricky to avoid
2908 // at this stage as we don't know what expressions follow base
2910 if (rc.CurrentAnonymousMethod != null) {
2911 if (targs == null && method.IsGeneric) {
2912 targs = method.TypeArguments;
2913 method = method.GetGenericMethodDefinition ();
2916 if (method.Parameters.HasArglist)
2917 throw new NotImplementedException ("__arglist base call proxy");
2919 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2921 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2922 // get/set member expressions second call would fail to proxy because left expression
2923 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
2924 // FIXME: The async check is another hack but will probably fail with mutators
2925 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
2926 InstanceExpression = new This (loc).Resolve (rc);
2930 method = method.MakeGenericMethod (rc, targs);
2934 // Only base will allow this invocation to happen.
2936 if (method.IsAbstract) {
2937 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2943 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2945 if (InstanceExpression == null)
2948 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2949 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
2950 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2955 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2957 if (InstanceExpression == null)
2960 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
2963 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
2965 var ct = rc.CurrentType;
2966 if (ct == qualifier)
2969 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2972 qualifier = qualifier.GetDefinition ();
2973 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2980 public override bool ContainsEmitWithAwait ()
2982 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2985 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2988 type = type.GetDefinition ();
2990 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2993 type = type.DeclaringType;
2994 } while (type != null);
2999 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3001 if (InstanceExpression != null) {
3002 InstanceExpression = InstanceExpression.Resolve (rc);
3003 CheckProtectedMemberAccess (rc, member);
3006 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3007 UnsafeError (rc, loc);
3010 var dep = member.GetMissingDependencies ();
3012 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3015 if (!rc.IsObsolete) {
3016 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3018 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3021 if (!(member is FieldSpec))
3022 member.MemberDefinition.SetIsUsed ();
3025 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3027 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3030 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3032 rc.Report.SymbolRelatedToPreviousError (member);
3033 rc.Report.Error (1540, loc,
3034 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3035 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3038 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3040 if (!ResolveInstanceExpressionCore (rc, rhs))
3044 // Check intermediate value modification which won't have any effect
3046 if (rhs != null && InstanceExpression.Type.IsStruct &&
3047 (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation)) {
3049 if (rc.CurrentInitializerVariable != null) {
3050 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3051 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3053 rc.Report.Error (1612, loc,
3054 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3055 InstanceExpression.GetSignatureForError ());
3062 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3065 if (InstanceExpression != null) {
3066 if (InstanceExpression is TypeExpr) {
3067 var t = InstanceExpression.Type;
3069 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3070 if (oa != null && !rc.IsObsolete) {
3071 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3074 t = t.DeclaringType;
3075 } while (t != null);
3077 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3078 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3079 rc.Report.Error (176, loc,
3080 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3081 GetSignatureForError ());
3085 InstanceExpression = null;
3091 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3092 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3093 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3094 rc.Report.Error (236, loc,
3095 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3096 GetSignatureForError ());
3098 rc.Report.Error (120, loc,
3099 "An object reference is required to access non-static member `{0}'",
3100 GetSignatureForError ());
3102 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3106 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3107 rc.Report.Error (38, loc,
3108 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3109 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3112 InstanceExpression = new This (loc);
3113 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3114 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
3115 InstanceExpression = InstanceExpression.Resolve (rc);
3118 InstanceExpression = InstanceExpression.Resolve (rc);
3124 var me = InstanceExpression as MemberExpr;
3126 me.ResolveInstanceExpressionCore (rc, rhs);
3128 // Using this check to detect probing instance expression resolve
3129 if (!rc.OmitStructFlowAnalysis) {
3130 var fe = me as FieldExpr;
3131 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3132 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3133 rc.Report.Warning (1690, 1, loc,
3134 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3135 me.GetSignatureForError ());
3143 // Run member-access postponed check once we know that
3144 // the expression is not field expression which is the only
3145 // expression which can use uninitialized this
3147 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3148 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3152 // Additional checks for l-value member access
3155 if (InstanceExpression is UnboxCast) {
3156 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3163 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3165 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3166 ec.Report.Warning (1720, 1, left.Location,
3167 "Expression will always cause a `{0}'", "System.NullReferenceException");
3170 InstanceExpression = left;
3174 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3176 TypeSpec instance_type = InstanceExpression.Type;
3177 if (TypeSpec.IsValueType (instance_type)) {
3178 if (InstanceExpression is IMemoryLocation) {
3179 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3181 // Cannot release the temporary variable when its address
3182 // is required to be on stack for any parent
3183 LocalTemporary t = new LocalTemporary (instance_type);
3184 InstanceExpression.Emit (ec);
3186 t.AddressOf (ec, AddressOp.Store);
3189 InstanceExpression.Emit (ec);
3191 // Only to make verifier happy
3192 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3193 ec.Emit (OpCodes.Box, instance_type);
3196 if (prepare_for_load)
3197 ec.Emit (OpCodes.Dup);
3200 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3203 public class ExtensionMethodCandidates
3205 readonly NamespaceContainer container;
3206 readonly IList<MethodSpec> methods;
3208 readonly IMemberContext context;
3210 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3212 this.context = context;
3213 this.methods = methods;
3214 this.container = nsContainer;
3215 this.index = lookupIndex;
3218 public NamespaceContainer Container {
3224 public IMemberContext Context {
3230 public int LookupIndex {
3236 public IList<MethodSpec> Methods {
3244 // Represents a group of extension method candidates for whole namespace
3246 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3248 ExtensionMethodCandidates candidates;
3249 public Expression ExtensionExpression;
3251 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3252 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3254 this.candidates = candidates;
3255 this.ExtensionExpression = extensionExpr;
3258 public override bool IsStatic {
3259 get { return true; }
3263 // For extension methodgroup we are not looking for base members but parent
3264 // namespace extension methods
3266 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3268 // TODO: candidates are null only when doing error reporting, that's
3269 // incorrect. We have to discover same extension methods in error mode
3270 if (candidates == null)
3273 int arity = type_arguments == null ? 0 : type_arguments.Count;
3275 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3276 if (candidates == null)
3279 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3282 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3284 // We are already here
3288 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3290 if (arguments == null)
3291 arguments = new Arguments (1);
3293 ExtensionExpression = ExtensionExpression.Resolve (ec);
3294 if (ExtensionExpression == null)
3297 var cand = candidates;
3298 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3299 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3301 // Restore candidates in case we are running in probing mode
3304 // Store resolved argument and restore original arguments
3306 // Clean-up modified arguments for error reporting
3307 arguments.RemoveAt (0);
3311 var me = ExtensionExpression as MemberExpr;
3313 me.ResolveInstanceExpression (ec, null);
3314 var fe = me as FieldExpr;
3316 fe.Spec.MemberDefinition.SetIsUsed ();
3319 InstanceExpression = null;
3323 #region IErrorHandler Members
3325 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3330 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3332 rc.Report.SymbolRelatedToPreviousError (best);
3333 rc.Report.Error (1928, loc,
3334 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3335 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3338 rc.Report.Error (1929, loc,
3339 "Extension method instance type `{0}' cannot be converted to `{1}'",
3340 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3346 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3351 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3360 /// MethodGroupExpr represents a group of method candidates which
3361 /// can be resolved to the best method overload
3363 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3365 protected IList<MemberSpec> Methods;
3366 MethodSpec best_candidate;
3367 TypeSpec best_candidate_return;
3368 protected TypeArguments type_arguments;
3370 SimpleName simple_name;
3371 protected TypeSpec queried_type;
3373 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3377 this.type = InternalType.MethodGroup;
3379 eclass = ExprClass.MethodGroup;
3380 queried_type = type;
3383 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3384 : this (new MemberSpec[] { m }, type, loc)
3390 public MethodSpec BestCandidate {
3392 return best_candidate;
3396 public TypeSpec BestCandidateReturnType {
3398 return best_candidate_return;
3402 public IList<MemberSpec> Candidates {
3408 protected override TypeSpec DeclaringType {
3410 return queried_type;
3414 public override bool IsInstance {
3416 if (best_candidate != null)
3417 return !best_candidate.IsStatic;
3423 public override bool IsStatic {
3425 if (best_candidate != null)
3426 return best_candidate.IsStatic;
3432 public override string KindName {
3433 get { return "method"; }
3436 public override string Name {
3438 if (best_candidate != null)
3439 return best_candidate.Name;
3442 return Methods.First ().Name;
3449 // When best candidate is already know this factory can be used
3450 // to avoid expensive overload resolution to be called
3452 // NOTE: InstanceExpression has to be set manually
3454 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3456 return new MethodGroupExpr (best, queriedType, loc) {
3457 best_candidate = best,
3458 best_candidate_return = best.ReturnType
3462 public override string GetSignatureForError ()
3464 if (best_candidate != null)
3465 return best_candidate.GetSignatureForError ();
3467 return Methods.First ().GetSignatureForError ();
3470 public override Expression CreateExpressionTree (ResolveContext ec)
3472 if (best_candidate == null) {
3473 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3477 if (best_candidate.IsConditionallyExcluded (ec, loc))
3478 ec.Report.Error (765, loc,
3479 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3481 return new TypeOfMethod (best_candidate, loc);
3484 protected override Expression DoResolve (ResolveContext ec)
3486 this.eclass = ExprClass.MethodGroup;
3488 if (InstanceExpression != null) {
3489 InstanceExpression = InstanceExpression.Resolve (ec);
3490 if (InstanceExpression == null)
3497 public override void Emit (EmitContext ec)
3499 throw new NotSupportedException ();
3502 public void EmitCall (EmitContext ec, Arguments arguments)
3504 var call = new CallEmitter ();
3505 call.InstanceExpression = InstanceExpression;
3506 call.Emit (ec, best_candidate, arguments, loc);
3509 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3511 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3512 Name, target.GetSignatureForError ());
3515 public static bool IsExtensionMethodArgument (Expression expr)
3518 // LAMESPEC: No details about which expressions are not allowed
3520 return !(expr is TypeExpr) && !(expr is BaseThis);
3524 /// Find the Applicable Function Members (7.4.2.1)
3526 /// me: Method Group expression with the members to select.
3527 /// it might contain constructors or methods (or anything
3528 /// that maps to a method).
3530 /// Arguments: ArrayList containing resolved Argument objects.
3532 /// loc: The location if we want an error to be reported, or a Null
3533 /// location for "probing" purposes.
3535 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3536 /// that is the best match of me on Arguments.
3539 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3541 // TODO: causes issues with probing mode, remove explicit Kind check
3542 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3545 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3546 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3547 r.BaseMembersProvider = this;
3548 r.InstanceQualifier = this;
3551 if (cerrors != null)
3552 r.CustomErrors = cerrors;
3554 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3555 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3556 if (best_candidate == null)
3557 return r.BestCandidateIsDynamic ? this : null;
3559 // Overload resolver had to create a new method group, all checks bellow have already been executed
3560 if (r.BestCandidateNewMethodGroup != null)
3561 return r.BestCandidateNewMethodGroup;
3563 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3564 if (InstanceExpression != null) {
3565 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3566 InstanceExpression = null;
3568 if (best_candidate.IsStatic && simple_name != null) {
3569 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3572 InstanceExpression.Resolve (ec);
3576 ResolveInstanceExpression (ec, null);
3579 var base_override = CandidateToBaseOverride (ec, best_candidate);
3580 if (base_override == best_candidate) {
3581 best_candidate_return = r.BestCandidateReturnType;
3583 best_candidate = base_override;
3584 best_candidate_return = best_candidate.ReturnType;
3587 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3588 ConstraintChecker cc = new ConstraintChecker (ec);
3589 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3593 // Additional check for possible imported base override method which
3594 // could not be done during IsOverrideMethodBaseTypeAccessible
3596 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3597 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3598 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3599 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3605 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3607 var fe = left as FieldExpr;
3610 // Using method-group on struct fields makes the struct assigned. I am not sure
3611 // why but that's what .net does
3613 fe.Spec.MemberDefinition.SetIsAssigned ();
3616 simple_name = original;
3617 return base.ResolveMemberAccess (ec, left, original);
3620 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3622 type_arguments = ta;
3625 #region IBaseMembersProvider Members
3627 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3629 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3632 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3634 if (queried_type == member.DeclaringType)
3637 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3638 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3642 // Extension methods lookup after ordinary methods candidates failed to apply
3644 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3646 if (InstanceExpression == null)
3649 InstanceExpression = InstanceExpression.Resolve (rc);
3650 if (!IsExtensionMethodArgument (InstanceExpression))
3653 int arity = type_arguments == null ? 0 : type_arguments.Count;
3654 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3655 if (methods == null)
3658 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3659 emg.SetTypeArguments (rc, type_arguments);
3666 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3668 public ConstructorInstanceQualifier (TypeSpec type)
3671 InstanceType = type;
3674 public TypeSpec InstanceType { get; private set; }
3676 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3678 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3682 public struct OverloadResolver
3685 public enum Restrictions
3689 ProbingOnly = 1 << 1,
3690 CovariantDelegate = 1 << 2,
3691 NoBaseMembers = 1 << 3,
3692 BaseMembersIncluded = 1 << 4
3695 public interface IBaseMembersProvider
3697 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3698 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3699 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3702 public interface IErrorHandler
3704 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3705 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3706 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3707 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3710 public interface IInstanceQualifier
3712 TypeSpec InstanceType { get; }
3713 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3716 sealed class NoBaseMembers : IBaseMembersProvider
3718 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3720 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3725 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3730 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3736 struct AmbiguousCandidate
3738 public readonly MemberSpec Member;
3739 public readonly bool Expanded;
3740 public readonly AParametersCollection Parameters;
3742 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3745 Parameters = parameters;
3746 Expanded = expanded;
3751 IList<MemberSpec> members;
3752 TypeArguments type_arguments;
3753 IBaseMembersProvider base_provider;
3754 IErrorHandler custom_errors;
3755 IInstanceQualifier instance_qualifier;
3756 Restrictions restrictions;
3757 MethodGroupExpr best_candidate_extension_group;
3758 TypeSpec best_candidate_return_type;
3760 SessionReportPrinter lambda_conv_msgs;
3762 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3763 : this (members, null, restrictions, loc)
3767 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3770 if (members == null || members.Count == 0)
3771 throw new ArgumentException ("empty members set");
3773 this.members = members;
3775 type_arguments = targs;
3776 this.restrictions = restrictions;
3777 if (IsDelegateInvoke)
3778 this.restrictions |= Restrictions.NoBaseMembers;
3780 base_provider = NoBaseMembers.Instance;
3785 public IBaseMembersProvider BaseMembersProvider {
3787 return base_provider;
3790 base_provider = value;
3794 public bool BestCandidateIsDynamic { get; set; }
3797 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3799 public MethodGroupExpr BestCandidateNewMethodGroup {
3801 return best_candidate_extension_group;
3806 // Return type can be different between best candidate and closest override
3808 public TypeSpec BestCandidateReturnType {
3810 return best_candidate_return_type;
3814 public IErrorHandler CustomErrors {
3816 return custom_errors;
3819 custom_errors = value;
3823 TypeSpec DelegateType {
3825 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3826 throw new InternalErrorException ("Not running in delegate mode", loc);
3828 return members [0].DeclaringType;
3832 public IInstanceQualifier InstanceQualifier {
3834 return instance_qualifier;
3837 instance_qualifier = value;
3841 bool IsProbingOnly {
3843 return (restrictions & Restrictions.ProbingOnly) != 0;
3847 bool IsDelegateInvoke {
3849 return (restrictions & Restrictions.DelegateInvoke) != 0;
3856 // 7.4.3.3 Better conversion from expression
3857 // Returns : 1 if a->p is better,
3858 // 2 if a->q is better,
3859 // 0 if neither is better
3861 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3863 TypeSpec argument_type = a.Type;
3866 // If argument is an anonymous function
3868 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3870 // p and q are delegate types or expression tree types
3872 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3873 if (q.MemberDefinition != p.MemberDefinition) {
3878 // Uwrap delegate from Expression<T>
3880 q = TypeManager.GetTypeArguments (q)[0];
3881 p = TypeManager.GetTypeArguments (p)[0];
3884 var p_m = Delegate.GetInvokeMethod (p);
3885 var q_m = Delegate.GetInvokeMethod (q);
3888 // With identical parameter lists
3890 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3899 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3901 if (p.Kind == MemberKind.Void) {
3902 return q.Kind != MemberKind.Void ? 2 : 0;
3906 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3908 if (q.Kind == MemberKind.Void) {
3909 return p.Kind != MemberKind.Void ? 1: 0;
3912 var am = (AnonymousMethodExpression) a.Expr;
3915 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3916 // better conversion is performed between underlying types Y1 and Y2
3918 if (p.IsGenericTask || q.IsGenericTask) {
3919 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
3920 q = q.TypeArguments[0];
3921 p = p.TypeArguments[0];
3923 } else if (q != p) {
3925 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
3927 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
3928 var am_rt = am.InferReturnType (ec, null, orig_q);
3929 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3931 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
3932 var am_rt = am.InferReturnType (ec, null, orig_p);
3933 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3939 // The parameters are identicial and return type is not void, use better type conversion
3940 // on return type to determine better one
3943 if (argument_type == p)
3946 if (argument_type == q)
3950 return BetterTypeConversion (ec, p, q);
3954 // 7.4.3.4 Better conversion from type
3956 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3958 if (p == null || q == null)
3959 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3961 switch (p.BuiltinType) {
3962 case BuiltinTypeSpec.Type.Int:
3963 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3966 case BuiltinTypeSpec.Type.Long:
3967 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3970 case BuiltinTypeSpec.Type.SByte:
3971 switch (q.BuiltinType) {
3972 case BuiltinTypeSpec.Type.Byte:
3973 case BuiltinTypeSpec.Type.UShort:
3974 case BuiltinTypeSpec.Type.UInt:
3975 case BuiltinTypeSpec.Type.ULong:
3979 case BuiltinTypeSpec.Type.Short:
3980 switch (q.BuiltinType) {
3981 case BuiltinTypeSpec.Type.UShort:
3982 case BuiltinTypeSpec.Type.UInt:
3983 case BuiltinTypeSpec.Type.ULong:
3987 case BuiltinTypeSpec.Type.Dynamic:
3988 // Dynamic is never better
3992 switch (q.BuiltinType) {
3993 case BuiltinTypeSpec.Type.Int:
3994 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3997 case BuiltinTypeSpec.Type.Long:
3998 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4001 case BuiltinTypeSpec.Type.SByte:
4002 switch (p.BuiltinType) {
4003 case BuiltinTypeSpec.Type.Byte:
4004 case BuiltinTypeSpec.Type.UShort:
4005 case BuiltinTypeSpec.Type.UInt:
4006 case BuiltinTypeSpec.Type.ULong:
4010 case BuiltinTypeSpec.Type.Short:
4011 switch (p.BuiltinType) {
4012 case BuiltinTypeSpec.Type.UShort:
4013 case BuiltinTypeSpec.Type.UInt:
4014 case BuiltinTypeSpec.Type.ULong:
4018 case BuiltinTypeSpec.Type.Dynamic:
4019 // Dynamic is never better
4023 // FIXME: handle lifted operators
4025 // TODO: this is expensive
4026 Expression p_tmp = new EmptyExpression (p);
4027 Expression q_tmp = new EmptyExpression (q);
4029 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4030 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4032 if (p_to_q && !q_to_p)
4035 if (q_to_p && !p_to_q)
4042 /// Determines "Better function" between candidate
4043 /// and the current best match
4046 /// Returns a boolean indicating :
4047 /// false if candidate ain't better
4048 /// true if candidate is better than the current best match
4050 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4051 MemberSpec best, AParametersCollection bparam, bool best_params)
4053 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4054 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4056 bool better_at_least_one = false;
4058 int args_count = args == null ? 0 : args.Count;
4062 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4065 // Default arguments are ignored for better decision
4066 if (a.IsDefaultArgument)
4070 // When comparing named argument the parameter type index has to be looked up
4071 // in original parameter set (override version for virtual members)
4073 NamedArgument na = a as NamedArgument;
4075 int idx = cparam.GetParameterIndexByName (na.Name);
4076 ct = candidate_pd.Types[idx];
4077 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4078 ct = TypeManager.GetElementType (ct);
4080 idx = bparam.GetParameterIndexByName (na.Name);
4081 bt = best_pd.Types[idx];
4082 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4083 bt = TypeManager.GetElementType (bt);
4085 ct = candidate_pd.Types[c_idx];
4086 bt = best_pd.Types[b_idx];
4088 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4089 ct = TypeManager.GetElementType (ct);
4093 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4094 bt = TypeManager.GetElementType (bt);
4099 if (TypeSpecComparer.IsEqual (ct, bt))
4103 int result = BetterExpressionConversion (ec, a, ct, bt);
4105 // for each argument, the conversion to 'ct' should be no worse than
4106 // the conversion to 'bt'.
4110 // for at least one argument, the conversion to 'ct' should be better than
4111 // the conversion to 'bt'.
4113 better_at_least_one = true;
4116 if (better_at_least_one)
4120 // This handles the case
4122 // Add (float f1, float f2, float f3);
4123 // Add (params decimal [] foo);
4125 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4126 // first candidate would've chosen as better.
4128 if (!same && !a.IsDefaultArgument)
4132 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4136 // This handles the following cases:
4138 // Foo (int i) is better than Foo (int i, long l = 0)
4139 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4140 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4142 // Prefer non-optional version
4144 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4146 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4147 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4150 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4153 return candidate_pd.Count >= best_pd.Count;
4157 // One is a non-generic method and second is a generic method, then non-generic is better
4159 if (best.IsGeneric != candidate.IsGeneric)
4160 return best.IsGeneric;
4163 // This handles the following cases:
4165 // Trim () is better than Trim (params char[] chars)
4166 // Concat (string s1, string s2, string s3) is better than
4167 // Concat (string s1, params string [] srest)
4168 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4170 // Prefer non-expanded version
4172 if (candidate_params != best_params)
4175 int candidate_param_count = candidate_pd.Count;
4176 int best_param_count = best_pd.Count;
4178 if (candidate_param_count != best_param_count)
4179 // can only happen if (candidate_params && best_params)
4180 return candidate_param_count > best_param_count && best_pd.HasParams;
4183 // Both methods have the same number of parameters, and the parameters have equal types
4184 // Pick the "more specific" signature using rules over original (non-inflated) types
4186 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4187 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4189 bool specific_at_least_once = false;
4190 for (j = 0; j < args_count; ++j) {
4191 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4193 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4194 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4196 ct = candidate_def_pd.Types[j];
4197 bt = best_def_pd.Types[j];
4202 TypeSpec specific = MoreSpecific (ct, bt);
4206 specific_at_least_once = true;
4209 if (specific_at_least_once)
4215 static bool CheckInflatedArguments (MethodSpec ms)
4217 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4220 // Setup constraint checker for probing only
4221 ConstraintChecker cc = new ConstraintChecker (null);
4223 var mp = ms.Parameters.Types;
4224 for (int i = 0; i < mp.Length; ++i) {
4225 var type = mp[i] as InflatedTypeSpec;
4229 var targs = type.TypeArguments;
4230 if (targs.Length == 0)
4233 // TODO: Checking inflated MVAR arguments should be enough
4234 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4241 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4243 rc.Report.Error (1729, loc,
4244 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4245 type.GetSignatureForError (), argCount.ToString ());
4249 // Determines if the candidate method is applicable to the given set of arguments
4250 // There could be two different set of parameters for same candidate where one
4251 // is the closest override for default values and named arguments checks and second
4252 // one being the virtual base for the parameter types and modifiers.
4254 // A return value rates candidate method compatibility,
4255 // 0 = the best, int.MaxValue = the worst
4258 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)
4260 // Parameters of most-derived type used mainly for named and optional parameters
4261 var pd = pm.Parameters;
4263 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4264 // params modifier instead of most-derived type
4265 var cpd = ((IParametersMember) candidate).Parameters;
4266 int param_count = pd.Count;
4267 int optional_count = 0;
4269 Arguments orig_args = arguments;
4271 if (arg_count != param_count) {
4273 // No arguments expansion when doing exact match for delegates
4275 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4276 for (int i = 0; i < pd.Count; ++i) {
4277 if (pd.FixedParameters[i].HasDefaultValue) {
4278 optional_count = pd.Count - i;
4284 if (optional_count != 0) {
4285 // Readjust expected number when params used
4286 if (cpd.HasParams) {
4288 if (arg_count < param_count)
4290 } else if (arg_count > param_count) {
4291 int args_gap = System.Math.Abs (arg_count - param_count);
4292 return int.MaxValue - 10000 + args_gap;
4293 } else if (arg_count < param_count - optional_count) {
4294 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4295 return int.MaxValue - 10000 + args_gap;
4297 } else if (arg_count != param_count) {
4298 int args_gap = System.Math.Abs (arg_count - param_count);
4300 return int.MaxValue - 10000 + args_gap;
4301 if (arg_count < param_count - 1)
4302 return int.MaxValue - 10000 + args_gap;
4305 // Resize to fit optional arguments
4306 if (optional_count != 0) {
4307 if (arguments == null) {
4308 arguments = new Arguments (optional_count);
4310 // Have to create a new container, so the next run can do same
4311 var resized = new Arguments (param_count);
4312 resized.AddRange (arguments);
4313 arguments = resized;
4316 for (int i = arg_count; i < param_count; ++i)
4317 arguments.Add (null);
4321 if (arg_count > 0) {
4323 // Shuffle named arguments to the right positions if there are any
4325 if (arguments[arg_count - 1] is NamedArgument) {
4326 arg_count = arguments.Count;
4328 for (int i = 0; i < arg_count; ++i) {
4329 bool arg_moved = false;
4331 NamedArgument na = arguments[i] as NamedArgument;
4335 int index = pd.GetParameterIndexByName (na.Name);
4337 // Named parameter not found
4341 // already reordered
4346 if (index >= param_count) {
4347 // When using parameters which should not be available to the user
4348 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4351 arguments.Add (null);
4355 temp = arguments[index];
4357 // The slot has been taken by positional argument
4358 if (temp != null && !(temp is NamedArgument))
4363 arguments = arguments.MarkOrderedArgument (na);
4367 arguments[index] = arguments[i];
4368 arguments[i] = temp;
4375 arg_count = arguments.Count;
4377 } else if (arguments != null) {
4378 arg_count = arguments.Count;
4382 // Don't do any expensive checks when the candidate cannot succeed
4384 if (arg_count != param_count && !cpd.HasParams)
4385 return (param_count - arg_count) * 2 + 1;
4387 var dep = candidate.GetMissingDependencies ();
4389 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4394 // 1. Handle generic method using type arguments when specified or type inference
4397 var ms = candidate as MethodSpec;
4398 if (ms != null && ms.IsGeneric) {
4399 if (type_arguments != null) {
4400 var g_args_count = ms.Arity;
4401 if (g_args_count != type_arguments.Count)
4402 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4404 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4407 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4408 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4409 // candidate was found use the set to report more details about what was wrong with lambda body.
4410 // The general idea is to distinguish between code errors and errors caused by
4411 // trial-and-error type inference
4413 if (lambda_conv_msgs == null) {
4414 for (int i = 0; i < arg_count; i++) {
4415 Argument a = arguments[i];
4419 var am = a.Expr as AnonymousMethodExpression;
4421 if (lambda_conv_msgs == null)
4422 lambda_conv_msgs = new SessionReportPrinter ();
4424 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4429 var ti = new TypeInference (arguments);
4430 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4433 return ti.InferenceScore - 20000;
4436 // Clear any error messages when the result was success
4438 if (lambda_conv_msgs != null)
4439 lambda_conv_msgs.ClearSession ();
4441 if (i_args.Length != 0) {
4442 ms = ms.MakeGenericMethod (ec, i_args);
4447 // Type arguments constraints have to match for the method to be applicable
4449 if (!CheckInflatedArguments (ms)) {
4451 return int.MaxValue - 25000;
4455 // We have a generic return type and at same time the method is override which
4456 // means we have to also inflate override return type in case the candidate is
4457 // best candidate and override return type is different to base return type.
4459 // virtual Foo<T, object> with override Foo<T, dynamic>
4461 if (candidate != pm) {
4462 MethodSpec override_ms = (MethodSpec) pm;
4463 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4464 returnType = inflator.Inflate (returnType);
4466 returnType = ms.ReturnType;
4473 if (type_arguments != null)
4474 return int.MaxValue - 15000;
4480 // 2. Each argument has to be implicitly convertible to method parameter
4482 Parameter.Modifier p_mod = 0;
4485 for (int i = 0; i < arg_count; i++) {
4486 Argument a = arguments[i];
4488 var fp = pd.FixedParameters[i];
4489 if (!fp.HasDefaultValue) {
4490 arguments = orig_args;
4491 return arg_count * 2 + 2;
4495 // Get the default value expression, we can use the same expression
4496 // if the type matches
4498 Expression e = fp.DefaultValue;
4500 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4502 // Restore for possible error reporting
4503 for (int ii = i; ii < arg_count; ++ii)
4504 arguments.RemoveAt (i);
4506 return (arg_count - i) * 2 + 1;
4510 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4512 // LAMESPEC: Attributes can be mixed together with build-in priority
4514 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4515 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4516 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4517 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4518 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4519 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4523 arguments[i] = new Argument (e, Argument.AType.Default);
4527 if (p_mod != Parameter.Modifier.PARAMS) {
4528 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4530 } else if (!params_expanded_form) {
4531 params_expanded_form = true;
4532 pt = ((ElementTypeSpec) pt).Element;
4538 if (!params_expanded_form) {
4539 if (a.ArgType == Argument.AType.ExtensionType) {
4541 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4543 // LAMESPEC: or implicit type parameter conversion
4546 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4547 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4548 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4553 score = IsArgumentCompatible (ec, a, p_mod, pt);
4556 dynamicArgument = true;
4561 // It can be applicable in expanded form (when not doing exact match like for delegates)
4563 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4564 if (!params_expanded_form) {
4565 pt = ((ElementTypeSpec) pt).Element;
4569 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4572 params_expanded_form = true;
4573 dynamicArgument = true;
4574 } else if (score == 0 || arg_count > pd.Count) {
4575 params_expanded_form = true;
4580 if (params_expanded_form)
4582 return (arg_count - i) * 2 + score;
4587 // When params parameter has no argument it will be provided later if the method is the best candidate
4589 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4590 params_expanded_form = true;
4593 // Restore original arguments for dynamic binder to keep the intention of original source code
4595 if (dynamicArgument)
4596 arguments = orig_args;
4601 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4603 if (e is Constant && e.Type == ptype)
4607 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4609 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4610 e = new MemberAccess (new MemberAccess (new MemberAccess (
4611 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4612 } else if (e is Constant) {
4614 // Handles int to int? conversions, DefaultParameterValue check
4616 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4620 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4623 return e.Resolve (ec);
4627 // Tests argument compatibility with the parameter
4628 // The possible return values are
4630 // 1 - modifier mismatch
4631 // 2 - type mismatch
4632 // -1 - dynamic binding required
4634 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4637 // Types have to be identical when ref or out modifer
4638 // is used and argument is not of dynamic type
4640 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4641 if (argument.Type != parameter) {
4643 // Do full equality check after quick path
4645 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4647 // Using dynamic for ref/out parameter can still succeed at runtime
4649 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4656 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4658 // Using dynamic for ref/out parameter can still succeed at runtime
4660 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4667 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4671 // Use implicit conversion in all modes to return same candidates when the expression
4672 // is used as argument or delegate conversion
4674 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4682 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4684 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4686 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4689 var ac_p = p as ArrayContainer;
4691 var ac_q = q as ArrayContainer;
4695 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4696 if (specific == ac_p.Element)
4698 if (specific == ac_q.Element)
4700 } else if (p.IsGeneric && q.IsGeneric) {
4701 var pargs = TypeManager.GetTypeArguments (p);
4702 var qargs = TypeManager.GetTypeArguments (q);
4704 bool p_specific_at_least_once = false;
4705 bool q_specific_at_least_once = false;
4707 for (int i = 0; i < pargs.Length; i++) {
4708 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4709 if (specific == pargs[i])
4710 p_specific_at_least_once = true;
4711 if (specific == qargs[i])
4712 q_specific_at_least_once = true;
4715 if (p_specific_at_least_once && !q_specific_at_least_once)
4717 if (!p_specific_at_least_once && q_specific_at_least_once)
4725 // Find the best method from candidate list
4727 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4729 List<AmbiguousCandidate> ambiguous_candidates = null;
4731 MemberSpec best_candidate;
4732 Arguments best_candidate_args = null;
4733 bool best_candidate_params = false;
4734 bool best_candidate_dynamic = false;
4735 int best_candidate_rate;
4736 IParametersMember best_parameter_member = null;
4738 int args_count = args != null ? args.Count : 0;
4740 Arguments candidate_args = args;
4741 bool error_mode = false;
4742 MemberSpec invocable_member = null;
4745 best_candidate = null;
4746 best_candidate_rate = int.MaxValue;
4748 var type_members = members;
4750 for (int i = 0; i < type_members.Count; ++i) {
4751 var member = type_members[i];
4754 // Methods in a base class are not candidates if any method in a derived
4755 // class is applicable
4757 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4761 if (!member.IsAccessible (rc))
4764 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4767 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4768 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4773 IParametersMember pm = member as IParametersMember;
4776 // Will use it later to report ambiguity between best method and invocable member
4778 if (Invocation.IsMemberInvocable (member))
4779 invocable_member = member;
4785 // Overload resolution is looking for base member but using parameter names
4786 // and default values from the closest member. That means to do expensive lookup
4787 // for the closest override for virtual or abstract members
4789 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4790 var override_params = base_provider.GetOverrideMemberParameters (member);
4791 if (override_params != null)
4792 pm = override_params;
4796 // Check if the member candidate is applicable
4798 bool params_expanded_form = false;
4799 bool dynamic_argument = false;
4800 TypeSpec rt = pm.MemberType;
4801 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4803 if (lambda_conv_msgs != null)
4804 lambda_conv_msgs.EndSession ();
4807 // How does it score compare to others
4809 if (candidate_rate < best_candidate_rate) {
4811 // Fatal error (missing dependency), cannot continue
4812 if (candidate_rate < 0)
4815 best_candidate_rate = candidate_rate;
4816 best_candidate = member;
4817 best_candidate_args = candidate_args;
4818 best_candidate_params = params_expanded_form;
4819 best_candidate_dynamic = dynamic_argument;
4820 best_parameter_member = pm;
4821 best_candidate_return_type = rt;
4822 } else if (candidate_rate == 0) {
4824 // The member look is done per type for most operations but sometimes
4825 // it's not possible like for binary operators overload because they
4826 // are unioned between 2 sides
4828 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4829 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4834 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4836 // We pack all interface members into top level type which makes the overload resolution
4837 // more complicated for interfaces. We compensate it by removing methods with same
4838 // signature when building the cache hence this path should not really be hit often
4841 // interface IA { void Foo (int arg); }
4842 // interface IB : IA { void Foo (params int[] args); }
4844 // IB::Foo is the best overload when calling IB.Foo (1)
4847 if (ambiguous_candidates != null) {
4848 foreach (var amb_cand in ambiguous_candidates) {
4849 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4858 ambiguous_candidates = null;
4861 // Is the new candidate better
4862 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4866 best_candidate = member;
4867 best_candidate_args = candidate_args;
4868 best_candidate_params = params_expanded_form;
4869 best_candidate_dynamic = dynamic_argument;
4870 best_parameter_member = pm;
4871 best_candidate_return_type = rt;
4873 // It's not better but any other found later could be but we are not sure yet
4874 if (ambiguous_candidates == null)
4875 ambiguous_candidates = new List<AmbiguousCandidate> ();
4877 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4881 // Restore expanded arguments
4882 if (candidate_args != args)
4883 candidate_args = args;
4885 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4888 // We've found exact match
4890 if (best_candidate_rate == 0)
4894 // Try extension methods lookup when no ordinary method match was found and provider enables it
4897 var emg = base_provider.LookupExtensionMethod (rc);
4899 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4901 best_candidate_extension_group = emg;
4902 return (T) (MemberSpec) emg.BestCandidate;
4907 // Don't run expensive error reporting mode for probing
4914 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
4917 lambda_conv_msgs = null;
4922 // No best member match found, report an error
4924 if (best_candidate_rate != 0 || error_mode) {
4925 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4929 if (best_candidate_dynamic) {
4930 if (args[0].ArgType == Argument.AType.ExtensionType) {
4931 rc.Report.Error (1973, loc,
4932 "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",
4933 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4937 // Check type constraints only when explicit type arguments are used
4939 if (best_candidate.IsGeneric && type_arguments != null) {
4940 MethodSpec bc = best_candidate as MethodSpec;
4941 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
4942 ConstraintChecker cc = new ConstraintChecker (rc);
4943 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
4947 BestCandidateIsDynamic = true;
4952 // These flags indicates we are running delegate probing conversion. No need to
4953 // do more expensive checks
4955 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4956 return (T) best_candidate;
4958 if (ambiguous_candidates != null) {
4960 // Now check that there are no ambiguities i.e the selected method
4961 // should be better than all the others
4963 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4964 var candidate = ambiguous_candidates [ix];
4966 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4967 var ambiguous = candidate.Member;
4968 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4969 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4970 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4971 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4972 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4975 return (T) best_candidate;
4980 if (invocable_member != null && !IsProbingOnly) {
4981 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4982 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4983 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4984 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4988 // And now check if the arguments are all
4989 // compatible, perform conversions if
4990 // necessary etc. and return if everything is
4993 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4996 if (best_candidate == null)
5000 // Don't run possibly expensive checks in probing mode
5002 if (!IsProbingOnly && !rc.IsInProbingMode) {
5004 // Check ObsoleteAttribute on the best method
5006 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5007 if (oa != null && !rc.IsObsolete)
5008 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5010 best_candidate.MemberDefinition.SetIsUsed ();
5013 args = best_candidate_args;
5014 return (T) best_candidate;
5017 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5019 return ResolveMember<MethodSpec> (rc, ref args);
5022 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5023 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5025 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5028 if (a.Type == InternalType.ErrorType)
5031 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5032 ec.Report.SymbolRelatedToPreviousError (method);
5033 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5034 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5035 TypeManager.CSharpSignature (method));
5038 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5039 TypeManager.CSharpSignature (method));
5040 } else if (IsDelegateInvoke) {
5041 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5042 DelegateType.GetSignatureForError ());
5044 ec.Report.SymbolRelatedToPreviousError (method);
5045 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5046 method.GetSignatureForError ());
5049 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5051 string index = (idx + 1).ToString ();
5052 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5053 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5054 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5055 index, Parameter.GetModifierSignature (a.Modifier));
5057 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5058 index, Parameter.GetModifierSignature (mod));
5060 string p1 = a.GetSignatureForError ();
5061 string p2 = paramType.GetSignatureForError ();
5064 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5065 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5068 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5069 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5070 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5073 ec.Report.Error (1503, a.Expr.Location,
5074 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5079 // We have failed to find exact match so we return error info about the closest match
5081 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5083 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5084 int arg_count = args == null ? 0 : args.Count;
5086 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5087 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5088 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
5092 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5097 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5098 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5099 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5103 // For candidates which match on parameters count report more details about incorrect arguments
5106 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5107 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5108 // Reject any inaccessible member
5109 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5110 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5111 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5115 var ms = best_candidate as MethodSpec;
5116 if (ms != null && ms.IsGeneric) {
5117 bool constr_ok = true;
5118 if (ms.TypeArguments != null)
5119 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5121 if (ta_count == 0) {
5122 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5126 rc.Report.Error (411, loc,
5127 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5128 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5135 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5141 // We failed to find any method with correct argument count, report best candidate
5143 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5146 if (best_candidate.Kind == MemberKind.Constructor) {
5147 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5148 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5149 } else if (IsDelegateInvoke) {
5150 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5151 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5152 DelegateType.GetSignatureForError (), arg_count.ToString ());
5154 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5155 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5156 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5157 name, arg_count.ToString ());
5161 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5163 var pd = pm.Parameters;
5164 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5166 Parameter.Modifier p_mod = 0;
5168 int a_idx = 0, a_pos = 0;
5170 ArrayInitializer params_initializers = null;
5171 bool has_unsafe_arg = pm.MemberType.IsPointer;
5172 int arg_count = args == null ? 0 : args.Count;
5174 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5176 if (p_mod != Parameter.Modifier.PARAMS) {
5177 p_mod = pd.FixedParameters[a_idx].ModFlags;
5179 has_unsafe_arg |= pt.IsPointer;
5181 if (p_mod == Parameter.Modifier.PARAMS) {
5182 if (chose_params_expanded) {
5183 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5184 pt = TypeManager.GetElementType (pt);
5190 // Types have to be identical when ref or out modifer is used
5192 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5193 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5196 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5202 NamedArgument na = a as NamedArgument;
5204 int name_index = pd.GetParameterIndexByName (na.Name);
5205 if (name_index < 0 || name_index >= pd.Count) {
5206 if (IsDelegateInvoke) {
5207 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5208 ec.Report.Error (1746, na.Location,
5209 "The delegate `{0}' does not contain a parameter named `{1}'",
5210 DelegateType.GetSignatureForError (), na.Name);
5212 ec.Report.SymbolRelatedToPreviousError (member);
5213 ec.Report.Error (1739, na.Location,
5214 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5215 TypeManager.CSharpSignature (member), na.Name);
5217 } else if (args[name_index] != a) {
5218 if (IsDelegateInvoke)
5219 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5221 ec.Report.SymbolRelatedToPreviousError (member);
5223 ec.Report.Error (1744, na.Location,
5224 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5229 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5232 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5233 custom_errors.NoArgumentMatch (ec, member);
5237 Expression conv = null;
5238 if (a.ArgType == Argument.AType.ExtensionType) {
5239 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5242 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5244 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5247 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5254 // Convert params arguments to an array initializer
5256 if (params_initializers != null) {
5257 // we choose to use 'a.Expr' rather than 'conv' so that
5258 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5259 params_initializers.Add (a.Expr);
5260 args.RemoveAt (a_idx--);
5265 // Update the argument with the implicit conversion
5269 if (a_idx != arg_count) {
5270 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5275 // Fill not provided arguments required by params modifier
5277 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5279 args = new Arguments (1);
5281 pt = ptypes[pd.Count - 1];
5282 pt = TypeManager.GetElementType (pt);
5283 has_unsafe_arg |= pt.IsPointer;
5284 params_initializers = new ArrayInitializer (0, loc);
5288 // Append an array argument with all params arguments
5290 if (params_initializers != null) {
5291 args.Add (new Argument (
5292 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5296 if (has_unsafe_arg && !ec.IsUnsafe) {
5297 Expression.UnsafeError (ec, loc);
5301 // We could infer inaccesible type arguments
5303 if (type_arguments == null && member.IsGeneric) {
5304 var ms = (MethodSpec) member;
5305 foreach (var ta in ms.TypeArguments) {
5306 if (!ta.IsAccessible (ec)) {
5307 ec.Report.SymbolRelatedToPreviousError (ta);
5308 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5318 public class ConstantExpr : MemberExpr
5320 readonly ConstSpec constant;
5322 public ConstantExpr (ConstSpec constant, Location loc)
5324 this.constant = constant;
5328 public override string Name {
5329 get { throw new NotImplementedException (); }
5332 public override string KindName {
5333 get { return "constant"; }
5336 public override bool IsInstance {
5337 get { return !IsStatic; }
5340 public override bool IsStatic {
5341 get { return true; }
5344 protected override TypeSpec DeclaringType {
5345 get { return constant.DeclaringType; }
5348 public override Expression CreateExpressionTree (ResolveContext ec)
5350 throw new NotSupportedException ("ET");
5353 protected override Expression DoResolve (ResolveContext rc)
5355 ResolveInstanceExpression (rc, null);
5356 DoBestMemberChecks (rc, constant);
5358 var c = constant.GetConstant (rc);
5360 // Creates reference expression to the constant value
5361 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5364 public override void Emit (EmitContext ec)
5366 throw new NotSupportedException ();
5369 public override string GetSignatureForError ()
5371 return constant.GetSignatureForError ();
5374 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5376 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5381 // Fully resolved expression that references a Field
5383 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5385 protected FieldSpec spec;
5386 VariableInfo variable_info;
5388 LocalTemporary temp;
5391 protected FieldExpr (Location l)
5396 public FieldExpr (FieldSpec spec, Location loc)
5401 type = spec.MemberType;
5404 public FieldExpr (FieldBase fi, Location l)
5411 public override string Name {
5417 public bool IsHoisted {
5419 IVariableReference hv = InstanceExpression as IVariableReference;
5420 return hv != null && hv.IsHoisted;
5424 public override bool IsInstance {
5426 return !spec.IsStatic;
5430 public override bool IsStatic {
5432 return spec.IsStatic;
5436 public override string KindName {
5437 get { return "field"; }
5440 public FieldSpec Spec {
5446 protected override TypeSpec DeclaringType {
5448 return spec.DeclaringType;
5452 public VariableInfo VariableInfo {
5454 return variable_info;
5460 public override string GetSignatureForError ()
5462 return spec.GetSignatureForError ();
5465 public bool IsMarshalByRefAccess (ResolveContext rc)
5467 // Checks possible ldflda of field access expression
5468 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5469 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5470 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5473 public void SetHasAddressTaken ()
5475 IVariableReference vr = InstanceExpression as IVariableReference;
5477 vr.SetHasAddressTaken ();
5481 public override Expression CreateExpressionTree (ResolveContext ec)
5483 return CreateExpressionTree (ec, true);
5486 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5489 Expression instance;
5491 if (InstanceExpression == null) {
5492 instance = new NullLiteral (loc);
5493 } else if (convertInstance) {
5494 instance = InstanceExpression.CreateExpressionTree (ec);
5496 args = new Arguments (1);
5497 args.Add (new Argument (InstanceExpression));
5498 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5501 args = Arguments.CreateForExpressionTree (ec, null,
5503 CreateTypeOfExpression ());
5505 return CreateExpressionFactoryCall (ec, "Field", args);
5508 public Expression CreateTypeOfExpression ()
5510 return new TypeOfField (spec, loc);
5513 protected override Expression DoResolve (ResolveContext ec)
5515 spec.MemberDefinition.SetIsUsed ();
5517 return DoResolve (ec, null);
5520 Expression DoResolve (ResolveContext ec, Expression rhs)
5522 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5525 if (ResolveInstanceExpression (ec, rhs)) {
5526 // Resolve the field's instance expression while flow analysis is turned
5527 // off: when accessing a field "a.b", we must check whether the field
5528 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5530 if (lvalue_instance) {
5531 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5532 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5534 Expression right_side =
5535 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5537 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5540 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5541 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5545 if (InstanceExpression == null)
5549 DoBestMemberChecks (ec, spec);
5552 var fb = spec as FixedFieldSpec;
5553 IVariableReference var = InstanceExpression as IVariableReference;
5555 if (lvalue_instance && var != null && var.VariableInfo != null) {
5556 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5560 IFixedExpression fe = InstanceExpression as IFixedExpression;
5561 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5562 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5565 if (InstanceExpression.eclass != ExprClass.Variable) {
5566 ec.Report.SymbolRelatedToPreviousError (spec);
5567 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5568 TypeManager.GetFullNameSignature (spec));
5569 } else if (var != null && var.IsHoisted) {
5570 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5573 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5577 // Set flow-analysis variable info for struct member access. It will be check later
5578 // for precise error reporting
5580 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5581 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5582 if (rhs != null && variable_info != null)
5583 variable_info.SetStructFieldAssigned (ec, Name);
5586 eclass = ExprClass.Variable;
5590 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5595 var var = fe.InstanceExpression as IVariableReference;
5597 var vi = var.VariableInfo;
5599 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5601 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5603 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5610 fe = fe.InstanceExpression as FieldExpr;
5612 } while (fe != null);
5615 static readonly int [] codes = {
5616 191, // instance, write access
5617 192, // instance, out access
5618 198, // static, write access
5619 199, // static, out access
5620 1648, // member of value instance, write access
5621 1649, // member of value instance, out access
5622 1650, // member of value static, write access
5623 1651 // member of value static, out access
5626 static readonly string [] msgs = {
5627 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5628 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5629 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5630 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5631 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5632 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5633 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5634 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5637 // The return value is always null. Returning a value simplifies calling code.
5638 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5641 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5645 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5647 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5652 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5654 if (spec is FixedFieldSpec) {
5655 // It could be much better error message but we want to be error compatible
5656 Error_ValueAssignment (ec, right_side);
5659 Expression e = DoResolve (ec, right_side);
5664 spec.MemberDefinition.SetIsAssigned ();
5666 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5667 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5668 ec.Report.Warning (420, 1, loc,
5669 "`{0}': A volatile field references will not be treated as volatile",
5670 spec.GetSignatureForError ());
5673 if (spec.IsReadOnly) {
5674 // InitOnly fields can only be assigned in constructors or initializers
5675 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5676 return Report_AssignToReadonly (ec, right_side);
5678 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5680 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5681 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5682 return Report_AssignToReadonly (ec, right_side);
5683 // static InitOnly fields cannot be assigned-to in an instance constructor
5684 if (IsStatic && !ec.IsStatic)
5685 return Report_AssignToReadonly (ec, right_side);
5686 // instance constructors can't modify InitOnly fields of other instances of the same type
5687 if (!IsStatic && !(InstanceExpression is This))
5688 return Report_AssignToReadonly (ec, right_side);
5692 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5693 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5694 ec.Report.Warning (197, 1, loc,
5695 "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",
5696 GetSignatureForError ());
5699 eclass = ExprClass.Variable;
5703 public override int GetHashCode ()
5705 return spec.GetHashCode ();
5708 public bool IsFixed {
5711 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5713 IVariableReference variable = InstanceExpression as IVariableReference;
5714 if (variable != null)
5715 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5717 IFixedExpression fe = InstanceExpression as IFixedExpression;
5718 return fe != null && fe.IsFixed;
5722 public override bool Equals (object obj)
5724 FieldExpr fe = obj as FieldExpr;
5728 if (spec != fe.spec)
5731 if (InstanceExpression == null || fe.InstanceExpression == null)
5734 return InstanceExpression.Equals (fe.InstanceExpression);
5737 public void Emit (EmitContext ec, bool leave_copy)
5739 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5743 ec.Emit (OpCodes.Volatile);
5745 ec.Emit (OpCodes.Ldsfld, spec);
5748 EmitInstance (ec, false);
5750 // Optimization for build-in types
5751 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5752 ec.EmitLoadFromPtr (type);
5754 var ff = spec as FixedFieldSpec;
5756 ec.Emit (OpCodes.Ldflda, spec);
5757 ec.Emit (OpCodes.Ldflda, ff.Element);
5760 ec.Emit (OpCodes.Volatile);
5762 ec.Emit (OpCodes.Ldfld, spec);
5768 ec.Emit (OpCodes.Dup);
5770 temp = new LocalTemporary (this.Type);
5776 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5778 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5779 if (isCompound && !(source is DynamicExpressionStatement)) {
5780 if (has_await_source) {
5782 InstanceExpression = InstanceExpression.EmitToField (ec);
5789 if (has_await_source)
5790 source = source.EmitToField (ec);
5792 EmitInstance (ec, prepared);
5798 ec.Emit (OpCodes.Dup);
5800 temp = new LocalTemporary (this.Type);
5805 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5806 ec.Emit (OpCodes.Volatile);
5808 spec.MemberDefinition.SetIsAssigned ();
5811 ec.Emit (OpCodes.Stsfld, spec);
5813 ec.Emit (OpCodes.Stfld, spec);
5823 // Emits store to field with prepared values on stack
5825 public void EmitAssignFromStack (EmitContext ec)
5828 ec.Emit (OpCodes.Stsfld, spec);
5830 ec.Emit (OpCodes.Stfld, spec);
5834 public override void Emit (EmitContext ec)
5839 public override void EmitSideEffect (EmitContext ec)
5841 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5843 if (is_volatile) // || is_marshal_by_ref ())
5844 base.EmitSideEffect (ec);
5847 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5849 if ((mode & AddressOp.Store) != 0)
5850 spec.MemberDefinition.SetIsAssigned ();
5851 if ((mode & AddressOp.Load) != 0)
5852 spec.MemberDefinition.SetIsUsed ();
5855 // Handle initonly fields specially: make a copy and then
5856 // get the address of the copy.
5859 if (spec.IsReadOnly){
5861 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5873 var temp = ec.GetTemporaryLocal (type);
5874 ec.Emit (OpCodes.Stloc, temp);
5875 ec.Emit (OpCodes.Ldloca, temp);
5876 ec.FreeTemporaryLocal (temp, type);
5882 ec.Emit (OpCodes.Ldsflda, spec);
5885 EmitInstance (ec, false);
5886 ec.Emit (OpCodes.Ldflda, spec);
5890 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5892 return MakeExpression (ctx);
5895 public override SLE.Expression MakeExpression (BuilderContext ctx)
5898 return base.MakeExpression (ctx);
5900 return SLE.Expression.Field (
5901 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5902 spec.GetMetaInfo ());
5906 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5908 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5914 // Expression that evaluates to a Property.
5916 // This is not an LValue because we need to re-write the expression. We
5917 // can not take data from the stack and store it.
5919 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5921 Arguments arguments;
5923 public PropertyExpr (PropertySpec spec, Location l)
5926 best_candidate = spec;
5927 type = spec.MemberType;
5932 protected override Arguments Arguments {
5941 protected override TypeSpec DeclaringType {
5943 return best_candidate.DeclaringType;
5947 public override string Name {
5949 return best_candidate.Name;
5953 public override bool IsInstance {
5959 public override bool IsStatic {
5961 return best_candidate.IsStatic;
5965 public override string KindName {
5966 get { return "property"; }
5969 public PropertySpec PropertyInfo {
5971 return best_candidate;
5977 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
5979 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
5982 var args_count = arguments == null ? 0 : arguments.Count;
5983 if (args_count != body.Parameters.Count && args_count == 0)
5986 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
5987 mg.InstanceExpression = InstanceExpression;
5992 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5994 return new PropertyExpr (spec, loc) {
6000 public override Expression CreateExpressionTree (ResolveContext ec)
6003 if (IsSingleDimensionalArrayLength ()) {
6004 args = new Arguments (1);
6005 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6006 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6009 args = new Arguments (2);
6010 if (InstanceExpression == null)
6011 args.Add (new Argument (new NullLiteral (loc)));
6013 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6014 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6015 return CreateExpressionFactoryCall (ec, "Property", args);
6018 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6020 DoResolveLValue (rc, null);
6021 return new TypeOfMethod (Setter, loc);
6024 public override string GetSignatureForError ()
6026 return best_candidate.GetSignatureForError ();
6029 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6032 return base.MakeExpression (ctx);
6034 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6038 public override SLE.Expression MakeExpression (BuilderContext ctx)
6041 return base.MakeExpression (ctx);
6043 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6047 void Error_PropertyNotValid (ResolveContext ec)
6049 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6050 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6051 GetSignatureForError ());
6054 bool IsSingleDimensionalArrayLength ()
6056 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6059 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6060 return ac != null && ac.Rank == 1;
6063 public override void Emit (EmitContext ec, bool leave_copy)
6066 // Special case: length of single dimension array property is turned into ldlen
6068 if (IsSingleDimensionalArrayLength ()) {
6069 EmitInstance (ec, false);
6070 ec.Emit (OpCodes.Ldlen);
6071 ec.Emit (OpCodes.Conv_I4);
6075 base.Emit (ec, leave_copy);
6078 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6081 LocalTemporary await_source_arg = null;
6083 if (isCompound && !(source is DynamicExpressionStatement)) {
6084 emitting_compound_assignment = true;
6087 if (has_await_arguments) {
6088 await_source_arg = new LocalTemporary (Type);
6089 await_source_arg.Store (ec);
6091 args = new Arguments (1);
6092 args.Add (new Argument (await_source_arg));
6095 temp = await_source_arg;
6098 has_await_arguments = false;
6103 ec.Emit (OpCodes.Dup);
6104 temp = new LocalTemporary (this.Type);
6109 args = arguments == null ? new Arguments (1) : arguments;
6113 temp = new LocalTemporary (this.Type);
6115 args.Add (new Argument (temp));
6117 args.Add (new Argument (source));
6121 emitting_compound_assignment = false;
6123 var call = new CallEmitter ();
6124 call.InstanceExpression = InstanceExpression;
6126 call.InstanceExpressionOnStack = true;
6128 call.Emit (ec, Setter, args, loc);
6135 if (await_source_arg != null) {
6136 await_source_arg.Release (ec);
6140 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6142 eclass = ExprClass.PropertyAccess;
6144 if (best_candidate.IsNotCSharpCompatible) {
6145 Error_PropertyNotValid (rc);
6148 ResolveInstanceExpression (rc, right_side);
6150 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6151 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6152 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6154 type = p.MemberType;
6158 DoBestMemberChecks (rc, best_candidate);
6160 // Handling of com-imported properties with any number of default property parameters
6161 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6162 var p = best_candidate.Get.Parameters;
6163 arguments = new Arguments (p.Count);
6164 for (int i = 0; i < p.Count; ++i) {
6165 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6167 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6168 var p = best_candidate.Set.Parameters;
6169 arguments = new Arguments (p.Count - 1);
6170 for (int i = 0; i < p.Count - 1; ++i) {
6171 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6178 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6180 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6184 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6186 // getter and setter can be different for base calls
6187 MethodSpec getter, setter;
6188 protected T best_candidate;
6190 protected LocalTemporary temp;
6191 protected bool emitting_compound_assignment;
6192 protected bool has_await_arguments;
6194 protected PropertyOrIndexerExpr (Location l)
6201 protected abstract Arguments Arguments { get; set; }
6203 public MethodSpec Getter {
6212 public MethodSpec Setter {
6223 protected override Expression DoResolve (ResolveContext ec)
6225 if (eclass == ExprClass.Unresolved) {
6226 var expr = OverloadResolve (ec, null);
6231 return expr.Resolve (ec);
6234 if (!ResolveGetter (ec))
6240 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6242 if (right_side == EmptyExpression.OutAccess) {
6243 // TODO: best_candidate can be null at this point
6244 INamedBlockVariable variable = null;
6245 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6246 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6247 best_candidate.Name);
6249 right_side.DoResolveLValue (ec, this);
6254 if (eclass == ExprClass.Unresolved) {
6255 var expr = OverloadResolve (ec, right_side);
6260 return expr.ResolveLValue (ec, right_side);
6263 if (!ResolveSetter (ec))
6270 // Implements the IAssignMethod interface for assignments
6272 public virtual void Emit (EmitContext ec, bool leave_copy)
6274 var call = new CallEmitter ();
6275 call.InstanceExpression = InstanceExpression;
6276 if (has_await_arguments)
6277 call.HasAwaitArguments = true;
6279 call.DuplicateArguments = emitting_compound_assignment;
6281 call.Emit (ec, Getter, Arguments, loc);
6283 if (call.HasAwaitArguments) {
6284 InstanceExpression = call.InstanceExpression;
6285 Arguments = call.EmittedArguments;
6286 has_await_arguments = true;
6290 ec.Emit (OpCodes.Dup);
6291 temp = new LocalTemporary (Type);
6296 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6298 public override void Emit (EmitContext ec)
6303 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6305 has_await_arguments = true;
6310 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6312 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6314 bool ResolveGetter (ResolveContext rc)
6316 if (!best_candidate.HasGet) {
6317 if (InstanceExpression != EmptyExpression.Null) {
6318 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6319 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6320 best_candidate.GetSignatureForError ());
6323 } else if (!best_candidate.Get.IsAccessible (rc)) {
6324 if (best_candidate.HasDifferentAccessibility) {
6325 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6326 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6327 TypeManager.CSharpSignature (best_candidate));
6329 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6330 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6334 if (best_candidate.HasDifferentAccessibility) {
6335 CheckProtectedMemberAccess (rc, best_candidate.Get);
6338 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6342 bool ResolveSetter (ResolveContext rc)
6344 if (!best_candidate.HasSet) {
6345 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6346 GetSignatureForError ());
6350 if (!best_candidate.Set.IsAccessible (rc)) {
6351 if (best_candidate.HasDifferentAccessibility) {
6352 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6353 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6354 GetSignatureForError ());
6356 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6357 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6361 if (best_candidate.HasDifferentAccessibility)
6362 CheckProtectedMemberAccess (rc, best_candidate.Set);
6364 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6370 /// Fully resolved expression that evaluates to an Event
6372 public class EventExpr : MemberExpr, IAssignMethod
6374 readonly EventSpec spec;
6377 public EventExpr (EventSpec spec, Location loc)
6385 protected override TypeSpec DeclaringType {
6387 return spec.DeclaringType;
6391 public override string Name {
6397 public override bool IsInstance {
6399 return !spec.IsStatic;
6403 public override bool IsStatic {
6405 return spec.IsStatic;
6409 public override string KindName {
6410 get { return "event"; }
6413 public MethodSpec Operator {
6421 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6424 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6426 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6427 if (spec.BackingField != null &&
6428 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6430 spec.MemberDefinition.SetIsUsed ();
6432 if (!ec.IsObsolete) {
6433 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6435 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6438 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6439 Error_AssignmentEventOnly (ec);
6441 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6443 InstanceExpression = null;
6445 return ml.ResolveMemberAccess (ec, left, original);
6449 return base.ResolveMemberAccess (ec, left, original);
6452 public override Expression CreateExpressionTree (ResolveContext ec)
6454 throw new NotSupportedException ("ET");
6457 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6459 if (right_side == EmptyExpression.EventAddition) {
6460 op = spec.AccessorAdd;
6461 } else if (right_side == EmptyExpression.EventSubtraction) {
6462 op = spec.AccessorRemove;
6466 Error_AssignmentEventOnly (ec);
6470 op = CandidateToBaseOverride (ec, op);
6474 protected override Expression DoResolve (ResolveContext ec)
6476 eclass = ExprClass.EventAccess;
6477 type = spec.MemberType;
6479 ResolveInstanceExpression (ec, null);
6481 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6482 Error_AssignmentEventOnly (ec);
6485 DoBestMemberChecks (ec, spec);
6489 public override void Emit (EmitContext ec)
6491 throw new NotSupportedException ();
6492 //Error_CannotAssign ();
6495 #region IAssignMethod Members
6497 public void Emit (EmitContext ec, bool leave_copy)
6499 throw new NotImplementedException ();
6502 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6504 if (leave_copy || !isCompound)
6505 throw new NotImplementedException ("EventExpr::EmitAssign");
6507 Arguments args = new Arguments (1);
6508 args.Add (new Argument (source));
6510 var call = new CallEmitter ();
6511 call.InstanceExpression = InstanceExpression;
6512 call.Emit (ec, op, args, loc);
6517 void Error_AssignmentEventOnly (ResolveContext ec)
6519 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6520 ec.Report.Error (79, loc,
6521 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6522 GetSignatureForError ());
6524 ec.Report.Error (70, loc,
6525 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6526 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6530 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6532 name = name.Substring (0, name.LastIndexOf ('.'));
6533 base.Error_CannotCallAbstractBase (rc, name);
6536 public override string GetSignatureForError ()
6538 return TypeManager.CSharpSignature (spec);
6541 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6543 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6547 public class TemporaryVariableReference : VariableReference
6549 public class Declarator : Statement
6551 TemporaryVariableReference variable;
6553 public Declarator (TemporaryVariableReference variable)
6555 this.variable = variable;
6559 protected override void DoEmit (EmitContext ec)
6561 variable.li.CreateBuilder (ec);
6564 public override void Emit (EmitContext ec)
6566 // Don't create sequence point
6570 protected override void CloneTo (CloneContext clonectx, Statement target)
6578 public TemporaryVariableReference (LocalVariable li, Location loc)
6581 this.type = li.Type;
6585 public override bool IsLockedByStatement {
6593 public LocalVariable LocalInfo {
6599 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6601 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6602 return new TemporaryVariableReference (li, loc);
6605 protected override Expression DoResolve (ResolveContext ec)
6607 eclass = ExprClass.Variable;
6610 // Don't capture temporary variables except when using
6611 // state machine redirection and block yields
6613 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer &&
6614 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6615 ec.IsVariableCapturingRequired) {
6616 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6617 storey.CaptureLocalVariable (ec, li);
6623 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6625 return Resolve (ec);
6628 public override void Emit (EmitContext ec)
6630 li.CreateBuilder (ec);
6635 public void EmitAssign (EmitContext ec, Expression source)
6637 li.CreateBuilder (ec);
6639 EmitAssign (ec, source, false, false);
6642 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6644 return li.HoistedVariant;
6647 public override bool IsFixed {
6648 get { return true; }
6651 public override bool IsRef {
6652 get { return false; }
6655 public override string Name {
6656 get { throw new NotImplementedException (); }
6659 public override void SetHasAddressTaken ()
6661 throw new NotImplementedException ();
6664 protected override ILocalVariable Variable {
6668 public override VariableInfo VariableInfo {
6669 get { return null; }
6672 public override void VerifyAssigned (ResolveContext rc)
6678 /// Handles `var' contextual keyword; var becomes a keyword only
6679 /// if no type called var exists in a variable scope
6681 class VarExpr : SimpleName
6683 public VarExpr (Location loc)
6688 public bool InferType (ResolveContext ec, Expression right_side)
6691 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6693 type = right_side.Type;
6694 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6695 ec.Report.Error (815, loc,
6696 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6697 type.GetSignatureForError ());
6701 eclass = ExprClass.Variable;
6705 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6707 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6708 base.Error_TypeOrNamespaceNotFound (ec);
6710 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");