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
131 public ExprClass eclass;
132 protected TypeSpec type;
133 protected Location loc;
135 public TypeSpec Type {
137 set { type = value; }
140 public virtual bool IsSideEffectFree {
146 public Location Location {
150 public virtual bool IsNull {
157 // Used to workaround parser limitation where we cannot get
158 // start of statement expression location
160 public virtual Location StartLocation {
166 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
169 // Return method-group expression when the expression can be used as
170 // lambda replacement. A good example is array sorting where instead of
173 // Array.Sort (s, (a, b) => String.Compare (a, b));
175 // we can use method group directly
177 // Array.Sort (s, String.Compare);
179 // Correct overload will be used because we do the reduction after
180 // best candidate was found.
186 // Returns true when the expression during Emit phase breaks stack
187 // by using await expression
189 public virtual bool ContainsEmitWithAwait ()
195 /// Performs semantic analysis on the Expression
199 /// The Resolve method is invoked to perform the semantic analysis
202 /// The return value is an expression (it can be the
203 /// same expression in some cases) or a new
204 /// expression that better represents this node.
206 /// For example, optimizations of Unary (LiteralInt)
207 /// would return a new LiteralInt with a negated
210 /// If there is an error during semantic analysis,
211 /// then an error should be reported (using Report)
212 /// and a null value should be returned.
214 /// There are two side effects expected from calling
215 /// Resolve(): the the field variable "eclass" should
216 /// be set to any value of the enumeration
217 /// `ExprClass' and the type variable should be set
218 /// to a valid type (this is the type of the
221 protected abstract Expression DoResolve (ResolveContext rc);
223 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
229 // This is used if the expression should be resolved as a type or namespace name.
230 // the default implementation fails.
232 public virtual TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
234 var rc = mc as ResolveContext ?? new ResolveContext (mc);
235 Expression e = Resolve (rc);
237 e.Error_UnexpectedKind (rc, ResolveFlags.Type, loc);
242 protected void CheckExpressionVariable (ResolveContext rc)
244 if (rc.HasAny (ResolveContext.Options.BaseInitializer | ResolveContext.Options.FieldInitializerScope)) {
245 rc.Report.Error (8200, loc, "Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers");
246 } else if (rc.HasSet (ResolveContext.Options.QueryClauseScope)) {
247 rc.Report.Error (8201, loc, "Out variable and pattern variable declarations are not allowed within a query clause");
251 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
253 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
256 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
258 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
261 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
263 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
264 name, type.GetSignatureForError ());
267 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
269 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
272 public void Error_InvalidExpressionStatement (BlockContext bc)
274 Error_InvalidExpressionStatement (bc.Report, loc);
277 public void Error_InvalidExpressionStatement (Report report)
279 Error_InvalidExpressionStatement (report, loc);
282 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
284 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
287 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
289 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
292 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
294 // The error was already reported as CS1660
295 if (type == InternalType.AnonymousMethod)
298 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
301 if (type.MemberDefinition.DeclaringAssembly.IsMissing ||
302 target.MemberDefinition.DeclaringAssembly.IsMissing)
305 string from_type = type.GetSignatureForError ();
306 if (type.Kind == MemberKind.ByRef)
307 from_type = "ref " + from_type;
308 string to_type = target.GetSignatureForError ();
309 if (target.Kind == MemberKind.ByRef)
310 to_type = "ref " + to_type;
312 if (from_type == to_type) {
313 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
314 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
318 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
323 ec.Report.DisableReporting ();
324 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
325 ec.Report.EnableReporting ();
328 ec.Report.Error (266, loc,
329 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
332 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
337 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
339 // Better message for possible generic expressions
340 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
341 var report = context.Module.Compiler.Report;
342 report.SymbolRelatedToPreviousError (member);
343 if (member is TypeSpec)
344 member = ((TypeSpec) member).GetDefinition ();
346 member = ((MethodSpec) member).GetGenericMethodDefinition ();
348 string name = member.Kind == MemberKind.Method ? "method" : "type";
349 if (member.IsGeneric) {
350 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
351 name, member.GetSignatureForError (), member.Arity.ToString ());
353 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
354 name, member.GetSignatureForError ());
357 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
361 public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
363 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
367 public virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
369 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
372 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
374 ec.Report.SymbolRelatedToPreviousError (type);
375 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
376 type.GetSignatureForError (), name);
379 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
381 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
382 // Already reported as CS1612
383 } else if (rhs == EmptyExpression.OutAccess) {
384 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
386 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
390 protected void Error_VoidPointerOperation (ResolveContext rc)
392 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
395 public static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
397 rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
400 public ResolveFlags ExprClassToResolveFlags {
404 case ExprClass.Namespace:
405 return ResolveFlags.Type;
407 case ExprClass.MethodGroup:
408 return ResolveFlags.MethodGroup;
410 case ExprClass.TypeParameter:
411 return ResolveFlags.TypeParameter;
413 case ExprClass.Value:
414 case ExprClass.Variable:
415 case ExprClass.PropertyAccess:
416 case ExprClass.EventAccess:
417 case ExprClass.IndexerAccess:
418 return ResolveFlags.VariableOrValue;
421 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
427 // Implements identical simple name and type-name resolution
429 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
432 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
435 // 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
436 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
438 if (left is MemberExpr || left is VariableReference) {
439 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
440 if (identical_type != null && identical_type.Type == left.Type)
441 return identical_type;
447 public virtual string GetSignatureForError ()
449 return type.GetDefinition ().GetSignatureForError ();
452 public static bool IsNeverNull (Expression expr)
454 if (expr is This || expr is New || expr is ArrayCreation || expr is DelegateCreation || expr is ConditionalMemberAccess)
457 var c = expr as Constant;
461 var tc = expr as TypeCast;
463 return IsNeverNull (tc.Child);
468 protected static bool IsNullPropagatingValid (TypeSpec type)
471 case MemberKind.Struct:
472 return type.IsNullableType;
473 case MemberKind.Enum:
474 case MemberKind.Void:
475 case MemberKind.PointerType:
477 case MemberKind.InternalCompilerType:
478 return type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
479 case MemberKind.TypeParameter:
480 return !((TypeParameterSpec) type).IsValueType;
486 public virtual bool HasConditionalAccess ()
491 protected TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
493 var tps = type as TypeParameterSpec;
494 if (tps != null && !(tps.IsReferenceType || tps.IsValueType)) {
495 Error_OperatorCannotBeApplied (rc, loc, "?", type);
498 return TypeSpec.IsValueType (type) && !type.IsNullableType ?
499 Nullable.NullableInfo.MakeType (rc.Module, type) :
504 /// Resolves an expression and performs semantic analysis on it.
508 /// Currently Resolve wraps DoResolve to perform sanity
509 /// checking and assertion checking on what we expect from Resolve.
511 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
513 if (eclass != ExprClass.Unresolved) {
514 if ((flags & ExprClassToResolveFlags) == 0) {
515 Error_UnexpectedKind (ec, flags, loc);
529 if ((flags & e.ExprClassToResolveFlags) == 0) {
530 e.Error_UnexpectedKind (ec, flags, loc);
535 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
538 } catch (Exception ex) {
539 if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
540 ec.Report.Printer is NullReportPrinter)
543 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
544 return ErrorExpression.Instance; // TODO: Add location
549 /// Resolves an expression and performs semantic analysis on it.
551 public Expression Resolve (ResolveContext rc)
553 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
557 /// Resolves an expression for LValue assignment
561 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
562 /// checking and assertion checking on what we expect from Resolve
564 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
566 int errors = ec.Report.Errors;
567 //bool out_access = right_side == EmptyExpression.OutAccess;
569 Expression e = DoResolveLValue (ec, right_side);
571 //if (e != null && out_access && !(e is IMemoryLocation)) {
572 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
573 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
575 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
576 // e.GetType () + " " + e.GetSignatureForError ());
581 if (errors == ec.Report.Errors) {
582 Error_ValueAssignment (ec, right_side);
587 if (e.eclass == ExprClass.Unresolved)
588 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
590 if ((e.type == null) && !(e is GenericTypeExpr))
591 throw new Exception ("Expression " + e + " did not set its type after Resolve");
596 public Constant ResolveLabelConstant (ResolveContext rc)
598 var expr = Resolve (rc);
602 Constant c = expr as Constant;
604 if (expr.type != InternalType.ErrorType)
605 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
613 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
615 if (Attribute.IsValidArgumentType (parameterType)) {
616 rc.Module.Compiler.Report.Error (182, loc,
617 "An attribute argument must be a constant expression, typeof expression or array creation expression");
619 rc.Module.Compiler.Report.Error (181, loc,
620 "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
621 targetType.GetSignatureForError ());
626 /// Emits the code for the expression
630 /// The Emit method is invoked to generate the code
631 /// for the expression.
633 public abstract void Emit (EmitContext ec);
636 // Emit code to branch to @target if this expression is equivalent to @on_true.
637 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
638 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
639 // including the use of conditional branches. Note also that a branch MUST be emitted
640 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
643 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
646 // Emit this expression for its side effects, not for its value.
647 // The default implementation is to emit the value, and then throw it away.
648 // Subclasses can provide more efficient implementations, but those MUST be equivalent
649 public virtual void EmitSideEffect (EmitContext ec)
652 ec.Emit (OpCodes.Pop);
655 public virtual void EmitPrepare (EmitContext ec)
660 // Emits the expression into temporary field variable. The method
661 // should be used for await expressions only
663 public virtual Expression EmitToField (EmitContext ec)
666 // This is the await prepare Emit method. When emitting code like
667 // a + b we emit code like
673 // For await a + await b we have to interfere the flow to keep the
674 // stack clean because await yields from the expression. The emit
677 // a = a.EmitToField () // a is changed to temporary field access
678 // b = b.EmitToField ()
684 // The idea is to emit expression and leave the stack empty with
685 // result value still available.
687 // Expressions should override this default implementation when
688 // optimized version can be provided (e.g. FieldExpr)
691 // We can optimize for side-effect free expressions, they can be
692 // emitted out of order
694 if (IsSideEffectFree)
697 bool needs_temporary = ContainsEmitWithAwait ();
698 if (!needs_temporary)
701 // Emit original code
702 var field = EmitToFieldSource (ec);
705 // Store the result to temporary field when we
706 // cannot load `this' directly
708 field = ec.GetTemporaryField (type);
709 if (needs_temporary) {
711 // Create temporary local (we cannot load `this' before Emit)
713 var temp = ec.GetTemporaryLocal (type);
714 ec.Emit (OpCodes.Stloc, temp);
717 ec.Emit (OpCodes.Ldloc, temp);
718 field.EmitAssignFromStack (ec);
720 ec.FreeTemporaryLocal (temp, type);
722 field.EmitAssignFromStack (ec);
729 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
732 // Default implementation calls Emit method
738 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
740 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
741 bool contains_await = false;
743 for (int i = 1; i < expressions.Count; ++i) {
744 if (expressions[i].ContainsEmitWithAwait ()) {
745 contains_await = true;
750 if (contains_await) {
751 for (int i = 0; i < expressions.Count; ++i) {
752 expressions[i] = expressions[i].EmitToField (ec);
757 for (int i = 0; i < expressions.Count; ++i) {
758 expressions[i].Emit (ec);
763 /// Protected constructor. Only derivate types should
764 /// be able to be created
767 protected Expression ()
772 /// Returns a fully formed expression after a MemberLookup
775 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
777 if (spec is EventSpec)
778 return new EventExpr ((EventSpec) spec, loc);
779 if (spec is ConstSpec)
780 return new ConstantExpr ((ConstSpec) spec, loc);
781 if (spec is FieldSpec)
782 return new FieldExpr ((FieldSpec) spec, loc);
783 if (spec is PropertySpec)
784 return new PropertyExpr ((PropertySpec) spec, loc);
785 if (spec is TypeSpec)
786 return new TypeExpression (((TypeSpec) spec), loc);
791 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
793 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
796 case MemberKind.Struct:
797 // Every struct has implicit default constructor if not provided by user
801 rc.Report.SymbolRelatedToPreviousError (type);
802 // Report meaningful error for struct as they always have default ctor in C# context
803 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
805 case MemberKind.MissingType:
806 case MemberKind.InternalCompilerType:
807 // LAMESPEC: dynamic is not really object
808 // if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
812 rc.Report.SymbolRelatedToPreviousError (type);
813 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
814 type.GetSignatureForError ());
821 if (args == null && type.IsStruct) {
822 bool includes_empty = false;
823 foreach (MethodSpec ctor in ctors) {
824 if (ctor.Parameters.IsEmpty) {
825 includes_empty = true;
833 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
834 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
835 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
838 return r.ResolveMember<MethodSpec> (rc, ref args);
842 public enum MemberLookupRestrictions
848 EmptyArguments = 1 << 4,
849 IgnoreArity = 1 << 5,
850 IgnoreAmbiguity = 1 << 6,
851 NameOfExcluded = 1 << 7,
852 DontSetConditionalAccess = 1 << 8
856 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
857 // `qualifier_type' or null to lookup members in the current class.
859 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
861 var members = MemberCache.FindMembers (queried_type, name, false);
863 if (members != null) {
866 expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
870 if (members [0].DeclaringType.BaseType == null)
873 members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
874 } while (members != null);
877 var tps = queried_type as TypeParameterSpec;
879 members = MemberCache.FindInterfaceMembers (tps, name);
881 return MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
884 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
885 var ntuple = queried_type as NamedTupleSpec;
886 if (ntuple != null) {
887 var ms = ntuple.FindElement (rc, name, loc);
889 return ExprClassFromMemberInfo (ms, loc);
896 public static Expression MemberLookupToExpression (IMemberContext rc, IList<MemberSpec> members, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
898 MemberSpec non_method = null;
899 MemberSpec ambig_non_method = null;
901 for (int i = 0; i < members.Count; ++i) {
902 var member = members [i];
904 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
905 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
908 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
911 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
915 if (!member.IsAccessible (rc))
919 // With runtime binder we can have a situation where queried type is inaccessible
920 // because it came via dynamic object, the check about inconsisted accessibility
921 // had no effect as the type was unknown during compilation
924 // private class N { }
926 // public dynamic Foo ()
932 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
936 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
937 if (member is MethodSpec) {
938 return new MethodGroupExpr (members, queried_type, loc);
941 if (!Invocation.IsMemberInvocable (member))
945 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
947 } else if (!errorMode && !member.IsNotCSharpCompatible) {
949 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
950 // T has both an effective base class other than object and a non-empty effective interface set.
952 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
954 var tps = queried_type as TypeParameterSpec;
955 if (tps != null && tps.HasTypeConstraint) {
956 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
959 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
965 ambig_non_method = member;
969 if (non_method != null) {
970 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
971 var report = rc.Module.Compiler.Report;
972 report.SymbolRelatedToPreviousError (non_method);
973 report.SymbolRelatedToPreviousError (ambig_non_method);
974 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
975 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
978 if (non_method is MethodSpec)
979 return new MethodGroupExpr (members, queried_type, loc);
981 return ExprClassFromMemberInfo (non_method, loc);
987 protected static void Error_NamedArgument (NamedArgument na, Report Report)
989 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
992 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
994 throw new NotImplementedException ();
997 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
999 if (t == InternalType.ErrorType)
1002 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
1003 oper, t.GetSignatureForError ());
1006 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
1008 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
1011 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
1013 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1016 protected void Error_NullPropagatingLValue (ResolveContext rc)
1018 rc.Report.Error (-1030, loc, "The left-hand side of an assignment cannot contain a null propagating operator");
1021 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1025 public virtual Reachability MarkReachable (Reachability rc)
1031 // Special version of flow analysis for expressions which can return different
1032 // on-true and on-false result. Used by &&, ||, ?: expressions
1034 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1037 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1041 /// Returns an expression that can be used to invoke operator true
1042 /// on the expression if it exists.
1044 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1046 return GetOperatorTrueOrFalse (ec, e, true, loc);
1050 /// Returns an expression that can be used to invoke operator false
1051 /// on the expression if it exists.
1053 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1055 return GetOperatorTrueOrFalse (ec, e, false, loc);
1058 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1060 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1062 if (type.IsNullableType)
1063 type = Nullable.NullableInfo.GetUnderlyingType (type);
1065 var methods = MemberCache.GetUserOperator (type, op, false);
1066 if (methods == null)
1069 Arguments arguments = new Arguments (1);
1070 arguments.Add (new Argument (e));
1072 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1073 var oper = res.ResolveOperator (ec, ref arguments);
1078 return new UserOperatorCall (oper, arguments, null, loc);
1081 public virtual string ExprClassName
1085 case ExprClass.Unresolved:
1086 return "Unresolved";
1087 case ExprClass.Value:
1089 case ExprClass.Variable:
1091 case ExprClass.Namespace:
1093 case ExprClass.Type:
1095 case ExprClass.MethodGroup:
1096 return "method group";
1097 case ExprClass.PropertyAccess:
1098 return "property access";
1099 case ExprClass.EventAccess:
1100 return "event access";
1101 case ExprClass.IndexerAccess:
1102 return "indexer access";
1103 case ExprClass.Nothing:
1105 case ExprClass.TypeParameter:
1106 return "type parameter";
1108 throw new Exception ("Should not happen");
1113 /// Reports that we were expecting `expr' to be of class `expected'
1115 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1117 var name = memberExpr.GetSignatureForError ();
1119 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1122 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1124 string [] valid = new string [4];
1127 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1128 valid [count++] = "variable";
1129 valid [count++] = "value";
1132 if ((flags & ResolveFlags.Type) != 0)
1133 valid [count++] = "type";
1135 if ((flags & ResolveFlags.MethodGroup) != 0)
1136 valid [count++] = "method group";
1139 valid [count++] = "unknown";
1141 StringBuilder sb = new StringBuilder (valid [0]);
1142 for (int i = 1; i < count - 1; i++) {
1144 sb.Append (valid [i]);
1147 sb.Append ("' or `");
1148 sb.Append (valid [count - 1]);
1151 ec.Report.Error (119, loc,
1152 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1155 public static void UnsafeError (ResolveContext ec, Location loc)
1157 UnsafeError (ec.Report, loc);
1160 public static void UnsafeError (Report Report, Location loc)
1162 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1165 public static void UnsafeInsideIteratorError (ResolveContext rc, Location loc)
1167 UnsafeInsideIteratorError (rc.Report, loc);
1170 public static void UnsafeInsideIteratorError (Report report, Location loc)
1172 report.Error (1629, loc, "Unsafe code may not appear in iterators");
1176 // Converts `source' to an int, uint, long or ulong.
1178 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1180 var btypes = ec.BuiltinTypes;
1182 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1183 Arguments args = new Arguments (1);
1184 args.Add (new Argument (source));
1185 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, source.loc).Resolve (ec);
1188 Expression converted;
1190 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1191 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1192 if (converted == null)
1193 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1194 if (converted == null)
1195 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1196 if (converted == null)
1197 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1199 if (converted == null) {
1200 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1209 // Only positive constants are allowed at compile time
1211 Constant c = converted as Constant;
1212 if (c != null && c.IsNegative)
1213 Error_NegativeArrayIndex (ec, source.loc);
1215 // No conversion needed to array index
1216 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1219 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1222 public Expression MakePointerAccess (ResolveContext rc, TypeSpec type, Arguments args)
1224 if (args.Count != 1){
1225 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
1230 if (arg is NamedArgument)
1231 Error_NamedArgument ((NamedArgument) arg, rc.Report);
1233 var index = arg.Expr.Resolve (rc);
1237 index = ConvertExpressionToArrayIndex (rc, index, true);
1239 Expression p = new PointerArithmetic (Binary.Operator.Addition, this, index, type, loc);
1240 return new Indirection (p, loc);
1244 // Derived classes implement this method by cloning the fields that
1245 // could become altered during the Resolve stage
1247 // Only expressions that are created for the parser need to implement
1250 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1252 throw new NotImplementedException (
1254 "CloneTo not implemented for expression {0}", this.GetType ()));
1258 // Clones an expression created by the parser.
1260 // We only support expressions created by the parser so far, not
1261 // expressions that have been resolved (many more classes would need
1262 // to implement CloneTo).
1264 // This infrastructure is here merely for Lambda expressions which
1265 // compile the same code using different type values for the same
1266 // arguments to find the correct overload
1268 public virtual Expression Clone (CloneContext clonectx)
1270 Expression cloned = (Expression) MemberwiseClone ();
1271 CloneTo (clonectx, cloned);
1277 // Implementation of expression to expression tree conversion
1279 public abstract Expression CreateExpressionTree (ResolveContext ec);
1281 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1283 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1286 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1288 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1291 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1293 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1296 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1298 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1302 return new TypeExpression (t, loc);
1306 // Implemented by all expressions which support conversion from
1307 // compiler expression to invokable runtime expression. Used by
1308 // dynamic C# binder.
1310 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1312 throw new NotImplementedException ("MakeExpression for " + GetType ());
1315 public virtual object Accept (StructuralVisitor visitor)
1317 return visitor.Visit (this);
1322 /// This is just a base class for expressions that can
1323 /// appear on statements (invocations, object creation,
1324 /// assignments, post/pre increment and decrement). The idea
1325 /// being that they would support an extra Emition interface that
1326 /// does not leave a result on the stack.
1328 public abstract class ExpressionStatement : Expression
1330 public virtual ExpressionStatement ResolveStatement (BlockContext ec)
1332 Expression e = Resolve (ec);
1336 ExpressionStatement es = e as ExpressionStatement;
1337 if (es == null || e is AnonymousMethodBody) {
1338 var reduced = e as IReducedExpressionStatement;
1339 if (reduced != null) {
1340 return EmptyExpressionStatement.Instance;
1343 Error_InvalidExpressionStatement (ec);
1347 // This is quite expensive warning, try to limit the damage
1349 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1350 WarningAsyncWithoutWait (ec, e);
1356 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1358 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1359 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1364 // Need to do full resolve because GetAwaiter can be extension method
1365 // available only in this context
1367 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1371 var arguments = new Arguments (0);
1372 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1377 // Use same check rules as for real await
1379 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1380 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1383 bc.Report.Warning (4014, 1, e.Location,
1384 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1388 var inv = e as Invocation;
1389 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1390 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1391 bc.Report.Warning (4014, 1, e.Location,
1392 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1398 /// Requests the expression to be emitted in a `statement'
1399 /// context. This means that no new value is left on the
1400 /// stack after invoking this method (constrasted with
1401 /// Emit that will always leave a value on the stack).
1403 public abstract void EmitStatement (EmitContext ec);
1405 public override void EmitSideEffect (EmitContext ec)
1411 interface IReducedExpressionStatement
1416 /// This kind of cast is used to encapsulate the child
1417 /// whose type is child.Type into an expression that is
1418 /// reported to return "return_type". This is used to encapsulate
1419 /// expressions which have compatible types, but need to be dealt
1420 /// at higher levels with.
1422 /// For example, a "byte" expression could be encapsulated in one
1423 /// of these as an "unsigned int". The type for the expression
1424 /// would be "unsigned int".
1427 public abstract class TypeCast : Expression
1429 protected readonly Expression child;
1431 protected TypeCast (Expression child, TypeSpec return_type)
1433 eclass = child.eclass;
1434 loc = child.Location;
1439 public Expression Child {
1445 public override bool ContainsEmitWithAwait ()
1447 return child.ContainsEmitWithAwait ();
1450 public override Expression CreateExpressionTree (ResolveContext ec)
1452 Arguments args = new Arguments (2);
1453 args.Add (new Argument (child.CreateExpressionTree (ec)));
1454 args.Add (new Argument (new TypeOf (type, loc)));
1456 if (type.IsPointer || child.Type.IsPointer)
1457 Error_PointerInsideExpressionTree (ec);
1459 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1462 protected override Expression DoResolve (ResolveContext ec)
1464 // This should never be invoked, we are born in fully
1465 // initialized state.
1470 public override void Emit (EmitContext ec)
1475 public override void FlowAnalysis (FlowAnalysisContext fc)
1477 child.FlowAnalysis (fc);
1480 public override SLE.Expression MakeExpression (BuilderContext ctx)
1483 return base.MakeExpression (ctx);
1485 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1486 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1487 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1491 public override Reachability MarkReachable (Reachability rc)
1493 return child.MarkReachable (rc);
1496 protected override void CloneTo (CloneContext clonectx, Expression t)
1501 public override bool IsNull {
1502 get { return child.IsNull; }
1506 public class EmptyCast : TypeCast {
1507 EmptyCast (Expression child, TypeSpec target_type)
1508 : base (child, target_type)
1512 public static Expression Create (Expression child, TypeSpec type)
1514 Constant c = child as Constant;
1516 var enum_constant = c as EnumConstant;
1517 if (enum_constant != null)
1518 c = enum_constant.Child;
1520 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1524 var res = c.ConvertImplicitly (type);
1530 EmptyCast e = child as EmptyCast;
1532 return new EmptyCast (e.child, type);
1534 return new EmptyCast (child, type);
1537 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1539 child.EmitBranchable (ec, label, on_true);
1542 public override void EmitSideEffect (EmitContext ec)
1544 child.EmitSideEffect (ec);
1549 // Used for predefined type user operator (no obsolete check, etc.)
1551 public class OperatorCast : TypeCast
1553 readonly MethodSpec conversion_operator;
1555 public OperatorCast (Expression expr, TypeSpec target_type)
1556 : this (expr, target_type, target_type, false)
1560 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1561 : this (expr, target_type, target_type, find_explicit)
1565 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1566 : base (expr, returnType)
1568 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1569 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1572 foreach (MethodSpec oper in mi) {
1573 if (oper.ReturnType != returnType)
1576 if (oper.Parameters.Types[0] == expr.Type) {
1577 conversion_operator = oper;
1583 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1584 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1587 public override void Emit (EmitContext ec)
1590 ec.Emit (OpCodes.Call, conversion_operator);
1595 // Constant specialization of EmptyCast.
1596 // We need to special case this since an empty cast of
1597 // a constant is still a constant.
1599 public class EmptyConstantCast : Constant
1601 public readonly Constant child;
1603 public EmptyConstantCast (Constant child, TypeSpec type)
1604 : base (child.Location)
1607 throw new ArgumentNullException ("child");
1610 this.eclass = child.eclass;
1614 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1616 if (child.Type == target_type)
1619 // FIXME: check that 'type' can be converted to 'target_type' first
1620 return child.ConvertExplicitly (in_checked_context, target_type);
1623 public override Expression CreateExpressionTree (ResolveContext ec)
1625 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1626 child.CreateExpressionTree (ec),
1627 new TypeOf (type, loc));
1630 Error_PointerInsideExpressionTree (ec);
1632 return CreateExpressionFactoryCall (ec, "Convert", args);
1635 public override bool IsDefaultValue {
1636 get { return child.IsDefaultValue; }
1639 public override bool IsNegative {
1640 get { return child.IsNegative; }
1643 public override bool IsNull {
1644 get { return child.IsNull; }
1647 public override bool IsOneInteger {
1648 get { return child.IsOneInteger; }
1651 public override bool IsSideEffectFree {
1653 return child.IsSideEffectFree;
1657 public override bool IsZeroInteger {
1658 get { return child.IsZeroInteger; }
1661 public override void Emit (EmitContext ec)
1666 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1668 child.EmitBranchable (ec, label, on_true);
1670 // Only to make verifier happy
1671 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1672 ec.Emit (OpCodes.Unbox_Any, type);
1675 public override void EmitSideEffect (EmitContext ec)
1677 child.EmitSideEffect (ec);
1680 public override object GetValue ()
1682 return child.GetValue ();
1685 public override string GetValueAsLiteral ()
1687 return child.GetValueAsLiteral ();
1690 public override long GetValueAsLong ()
1692 return child.GetValueAsLong ();
1695 public override Constant ConvertImplicitly (TypeSpec target_type)
1697 if (type == target_type)
1700 // FIXME: Do we need to check user conversions?
1701 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1704 return child.ConvertImplicitly (target_type);
1709 /// This class is used to wrap literals which belong inside Enums
1711 public class EnumConstant : Constant
1713 public Constant Child;
1715 public EnumConstant (Constant child, TypeSpec enum_type)
1716 : base (child.Location)
1720 this.eclass = ExprClass.Value;
1721 this.type = enum_type;
1724 protected EnumConstant (Location loc)
1729 public override void Emit (EmitContext ec)
1734 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1736 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1739 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1741 Child.EmitBranchable (ec, label, on_true);
1744 public override void EmitSideEffect (EmitContext ec)
1746 Child.EmitSideEffect (ec);
1749 public override string GetSignatureForError()
1751 return Type.GetSignatureForError ();
1754 public override object GetValue ()
1756 return Child.GetValue ();
1760 public override object GetTypedValue ()
1763 // The method can be used in dynamic context only (on closed types)
1765 // System.Enum.ToObject cannot be called on dynamic types
1766 // EnumBuilder has to be used, but we cannot use EnumBuilder
1767 // because it does not properly support generics
1769 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1773 public override string GetValueAsLiteral ()
1775 return Child.GetValueAsLiteral ();
1778 public override long GetValueAsLong ()
1780 return Child.GetValueAsLong ();
1783 public EnumConstant Increment()
1785 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1788 public override bool IsDefaultValue {
1790 return Child.IsDefaultValue;
1794 public override bool IsSideEffectFree {
1796 return Child.IsSideEffectFree;
1800 public override bool IsZeroInteger {
1801 get { return Child.IsZeroInteger; }
1804 public override bool IsNegative {
1806 return Child.IsNegative;
1810 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1812 if (Child.Type == target_type)
1815 return Child.ConvertExplicitly (in_checked_context, target_type);
1818 public override Constant ConvertImplicitly (TypeSpec type)
1820 if (this.type == type) {
1824 if (!Convert.ImplicitStandardConversionExists (this, type)){
1828 return Child.ConvertImplicitly (type);
1833 /// This kind of cast is used to encapsulate Value Types in objects.
1835 /// The effect of it is to box the value type emitted by the previous
1838 public class BoxedCast : TypeCast {
1840 public BoxedCast (Expression expr, TypeSpec target_type)
1841 : base (expr, target_type)
1843 eclass = ExprClass.Value;
1846 protected override Expression DoResolve (ResolveContext ec)
1848 // This should never be invoked, we are born in fully
1849 // initialized state.
1854 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1856 // Only boxing to object type is supported
1857 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1858 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1862 enc.Encode (child.Type);
1863 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1866 public override void Emit (EmitContext ec)
1870 ec.Emit (OpCodes.Box, child.Type);
1873 public override void EmitSideEffect (EmitContext ec)
1875 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1876 // so, we need to emit the box+pop instructions in most cases
1877 if (child.Type.IsStruct &&
1878 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1879 child.EmitSideEffect (ec);
1881 base.EmitSideEffect (ec);
1885 public class UnboxCast : TypeCast {
1886 public UnboxCast (Expression expr, TypeSpec return_type)
1887 : base (expr, return_type)
1891 protected override Expression DoResolve (ResolveContext ec)
1893 // This should never be invoked, we are born in fully
1894 // initialized state.
1899 public override void Emit (EmitContext ec)
1903 ec.Emit (OpCodes.Unbox_Any, type);
1908 /// This is used to perform explicit numeric conversions.
1910 /// Explicit numeric conversions might trigger exceptions in a checked
1911 /// context, so they should generate the conv.ovf opcodes instead of
1914 public class ConvCast : TypeCast {
1915 public enum Mode : byte {
1916 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1918 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1919 U2_I1, U2_U1, U2_I2, U2_CH,
1920 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1921 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1922 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1923 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1924 CH_I1, CH_U1, CH_I2,
1925 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1926 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1932 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1933 : base (child, return_type)
1938 protected override Expression DoResolve (ResolveContext ec)
1940 // This should never be invoked, we are born in fully
1941 // initialized state.
1946 public override string ToString ()
1948 return String.Format ("ConvCast ({0}, {1})", mode, child);
1951 public override void Emit (EmitContext ec)
1957 public static void Emit (EmitContext ec, Mode mode)
1959 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1961 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1962 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1963 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1964 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1965 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1967 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1968 case Mode.U1_CH: /* nothing */ break;
1970 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1971 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1972 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1973 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1974 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1975 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1977 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1978 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1979 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1980 case Mode.U2_CH: /* nothing */ break;
1982 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1983 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1984 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1985 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1986 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1987 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1988 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1990 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1991 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1992 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1993 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1994 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1995 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1997 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1998 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1999 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2000 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2001 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2002 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2003 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2004 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2005 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
2007 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2008 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2009 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2010 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2011 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
2012 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
2013 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2014 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2015 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
2017 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2018 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2019 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2021 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2022 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2023 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2024 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2025 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2026 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2027 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2028 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2029 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2031 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2032 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2033 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2034 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2035 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2036 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2037 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2038 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2039 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2040 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2042 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2046 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2047 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2048 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2049 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2050 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2052 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2053 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2055 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2056 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2057 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2058 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2059 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2060 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2062 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2063 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2064 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2065 case Mode.U2_CH: /* nothing */ break;
2067 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2068 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2069 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2070 case Mode.I4_U4: /* nothing */ break;
2071 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2072 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2073 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2075 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2076 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2077 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2078 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2079 case Mode.U4_I4: /* nothing */ break;
2080 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2082 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2083 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2084 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2085 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2086 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2087 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2088 case Mode.I8_U8: /* nothing */ break;
2089 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2090 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2092 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2093 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2094 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2095 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2096 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2097 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2098 case Mode.U8_I8: /* nothing */ break;
2099 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2100 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2102 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2103 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2104 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2106 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2107 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2108 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2109 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2110 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2111 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2112 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2113 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2114 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2116 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2117 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2118 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2119 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2120 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2121 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2122 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2123 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2124 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2125 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2127 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2133 class OpcodeCast : TypeCast
2137 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2138 : base (child, return_type)
2143 protected override Expression DoResolve (ResolveContext ec)
2145 // This should never be invoked, we are born in fully
2146 // initialized state.
2151 public override void Emit (EmitContext ec)
2157 public TypeSpec UnderlyingType {
2158 get { return child.Type; }
2163 // Opcode casts expression with 2 opcodes but only
2164 // single expression tree node
2166 class OpcodeCastDuplex : OpcodeCast
2168 readonly OpCode second;
2170 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2171 : base (child, returnType, first)
2173 this.second = second;
2176 public override void Emit (EmitContext ec)
2184 /// This kind of cast is used to encapsulate a child and cast it
2185 /// to the class requested
2187 public sealed class ClassCast : TypeCast {
2188 readonly bool forced;
2190 public ClassCast (Expression child, TypeSpec return_type)
2191 : base (child, return_type)
2195 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2196 : base (child, return_type)
2198 this.forced = forced;
2201 public override void Emit (EmitContext ec)
2205 bool gen = TypeManager.IsGenericParameter (child.Type);
2207 ec.Emit (OpCodes.Box, child.Type);
2209 if (type.IsGenericParameter) {
2210 ec.Emit (OpCodes.Unbox_Any, type);
2217 ec.Emit (OpCodes.Castclass, type);
2222 // Created during resolving pahse when an expression is wrapped or constantified
2223 // and original expression can be used later (e.g. for expression trees)
2225 public class ReducedExpression : Expression
2227 public class ReducedConstantExpression : EmptyConstantCast
2229 readonly Expression orig_expr;
2231 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2232 : base (expr, expr.Type)
2234 this.orig_expr = orig_expr;
2237 public Expression OriginalExpression {
2243 public override Constant ConvertImplicitly (TypeSpec target_type)
2245 Constant c = base.ConvertImplicitly (target_type);
2247 c = new ReducedConstantExpression (c, orig_expr);
2252 public override Expression CreateExpressionTree (ResolveContext ec)
2254 return orig_expr.CreateExpressionTree (ec);
2257 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2259 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2261 c = new ReducedConstantExpression (c, orig_expr);
2265 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2268 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2270 if (orig_expr is Conditional)
2271 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2273 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2277 sealed class ReducedConstantStatement : ReducedConstantExpression, IReducedExpressionStatement
2279 public ReducedConstantStatement (Constant expr, Expression origExpr)
2280 : base (expr, origExpr)
2285 sealed class ReducedExpressionStatement : ExpressionStatement
2287 readonly Expression orig_expr;
2288 readonly ExpressionStatement stm;
2290 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2292 this.orig_expr = orig;
2294 this.eclass = stm.eclass;
2295 this.type = stm.Type;
2297 this.loc = orig.Location;
2300 public override bool ContainsEmitWithAwait ()
2302 return stm.ContainsEmitWithAwait ();
2305 public override Expression CreateExpressionTree (ResolveContext ec)
2307 return orig_expr.CreateExpressionTree (ec);
2310 protected override Expression DoResolve (ResolveContext ec)
2315 public override void Emit (EmitContext ec)
2320 public override void EmitStatement (EmitContext ec)
2322 stm.EmitStatement (ec);
2325 public override void FlowAnalysis (FlowAnalysisContext fc)
2327 stm.FlowAnalysis (fc);
2331 readonly Expression expr, orig_expr;
2333 private ReducedExpression (Expression expr, Expression orig_expr)
2336 this.eclass = expr.eclass;
2337 this.type = expr.Type;
2338 this.orig_expr = orig_expr;
2339 this.loc = orig_expr.Location;
2344 public override bool IsSideEffectFree {
2346 return expr.IsSideEffectFree;
2350 public Expression OriginalExpression {
2358 public override bool ContainsEmitWithAwait ()
2360 return expr.ContainsEmitWithAwait ();
2364 // Creates fully resolved expression switcher
2366 public static Constant Create (Constant expr, Expression originalExpr)
2368 if (expr.eclass == ExprClass.Unresolved)
2369 throw new ArgumentException ("Unresolved expression");
2371 if (originalExpr is ExpressionStatement)
2372 return new ReducedConstantStatement (expr, originalExpr);
2374 return new ReducedConstantExpression (expr, originalExpr);
2377 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2379 return new ReducedExpressionStatement (s, orig);
2382 public static Expression Create (Expression expr, Expression original_expr)
2384 return Create (expr, original_expr, true);
2388 // Creates unresolved reduce expression. The original expression has to be
2389 // already resolved. Created expression is constant based based on `expr'
2390 // value unless canBeConstant is used
2392 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2394 if (canBeConstant) {
2395 Constant c = expr as Constant;
2397 return Create (c, original_expr);
2400 ExpressionStatement s = expr as ExpressionStatement;
2402 return Create (s, original_expr);
2404 if (expr.eclass == ExprClass.Unresolved)
2405 throw new ArgumentException ("Unresolved expression");
2407 return new ReducedExpression (expr, original_expr);
2410 public override Expression CreateExpressionTree (ResolveContext ec)
2412 return orig_expr.CreateExpressionTree (ec);
2415 protected override Expression DoResolve (ResolveContext ec)
2420 public override void Emit (EmitContext ec)
2425 public override Expression EmitToField (EmitContext ec)
2427 return expr.EmitToField(ec);
2430 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2432 expr.EmitBranchable (ec, target, on_true);
2435 public override void FlowAnalysis (FlowAnalysisContext fc)
2437 orig_expr.FlowAnalysis (fc);
2440 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
2442 orig_expr.FlowAnalysisConditional (fc);
2445 public override SLE.Expression MakeExpression (BuilderContext ctx)
2447 return orig_expr.MakeExpression (ctx);
2450 public override Reachability MarkReachable (Reachability rc)
2452 return expr.MarkReachable (rc);
2457 // Standard composite pattern
2459 public abstract class CompositeExpression : Expression
2461 protected Expression expr;
2463 protected CompositeExpression (Expression expr)
2466 this.loc = expr.Location;
2469 public override bool ContainsEmitWithAwait ()
2471 return expr.ContainsEmitWithAwait ();
2474 public override Expression CreateExpressionTree (ResolveContext rc)
2476 return expr.CreateExpressionTree (rc);
2479 public Expression Child {
2480 get { return expr; }
2483 protected override Expression DoResolve (ResolveContext rc)
2485 expr = expr.Resolve (rc);
2490 eclass = expr.eclass;
2494 public override void Emit (EmitContext ec)
2499 public override bool IsNull {
2500 get { return expr.IsNull; }
2505 // Base of expressions used only to narrow resolve flow
2507 public abstract class ShimExpression : Expression
2509 protected Expression expr;
2511 protected ShimExpression (Expression expr)
2516 public Expression Expr {
2522 protected override void CloneTo (CloneContext clonectx, Expression t)
2527 ShimExpression target = (ShimExpression) t;
2528 target.expr = expr.Clone (clonectx);
2531 public override bool ContainsEmitWithAwait ()
2533 return expr.ContainsEmitWithAwait ();
2536 public override Expression CreateExpressionTree (ResolveContext ec)
2538 throw new NotSupportedException ("ET");
2541 public override void Emit (EmitContext ec)
2543 throw new InternalErrorException ("Missing Resolve call");
2547 public class UnreachableExpression : Expression
2549 public UnreachableExpression (Expression expr)
2551 this.loc = expr.Location;
2554 public override Expression CreateExpressionTree (ResolveContext ec)
2557 throw new NotImplementedException ();
2560 protected override Expression DoResolve (ResolveContext rc)
2562 throw new NotSupportedException ();
2565 public override void FlowAnalysis (FlowAnalysisContext fc)
2567 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2570 public override void Emit (EmitContext ec)
2574 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2580 // Unresolved type name expressions
2582 public abstract class ATypeNameExpression : FullNamedExpression
2585 protected TypeArguments targs;
2587 protected ATypeNameExpression (string name, Location l)
2593 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2600 protected ATypeNameExpression (string name, int arity, Location l)
2601 : this (name, new UnboundTypeArguments (arity, l), l)
2609 return targs == null ? 0 : targs.Count;
2613 public bool HasTypeArguments {
2615 return targs != null && !targs.IsEmpty;
2619 public string Name {
2628 public TypeArguments TypeArguments {
2636 public override bool Equals (object obj)
2638 ATypeNameExpression atne = obj as ATypeNameExpression;
2639 return atne != null && atne.Name == Name &&
2640 (targs == null || targs.Equals (atne.targs));
2643 public override int GetHashCode ()
2645 return Name.GetHashCode ();
2648 // TODO: Move it to MemberCore
2649 public static string GetMemberType (MemberCore mc)
2655 if (mc is FieldBase)
2657 if (mc is MethodCore)
2659 if (mc is EnumMember)
2667 public override string GetSignatureForError ()
2669 if (targs != null) {
2670 return Name + "<" + targs.GetSignatureForError () + ">";
2676 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2680 /// SimpleName expressions are formed of a single word and only happen at the beginning
2681 /// of a dotted-name.
2683 public class SimpleName : ATypeNameExpression
2685 public SimpleName (string name, Location l)
2690 public SimpleName (string name, TypeArguments args, Location l)
2691 : base (name, args, l)
2695 public SimpleName (string name, int arity, Location l)
2696 : base (name, arity, l)
2700 public SimpleName GetMethodGroup ()
2702 return new SimpleName (Name, targs, loc);
2705 protected override Expression DoResolve (ResolveContext rc)
2707 return SimpleNameResolve (rc, null);
2710 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2712 return SimpleNameResolve (ec, right_side);
2715 public void Error_NameDoesNotExist (ResolveContext rc)
2717 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2720 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2722 if (ctx.CurrentType != null) {
2723 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2724 if (member != null) {
2725 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2730 var report = ctx.Module.Compiler.Report;
2732 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2733 if (retval != null) {
2734 report.SymbolRelatedToPreviousError (retval.Type);
2735 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2739 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2740 if (retval != null) {
2741 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2745 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2746 if (ns_candidates != null) {
2747 if (ctx is UsingAliasNamespace.AliasContext) {
2748 report.Error (246, loc,
2749 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2750 ns_candidates[0], Name);
2752 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2753 report.Error (246, loc,
2754 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2758 report.Error (246, loc,
2759 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2764 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2766 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2769 if (fne.Type != null && Arity > 0) {
2770 if (HasTypeArguments) {
2771 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2772 if (ct.ResolveAsType (mc) == null)
2778 targs.Resolve (mc, allowUnboundTypeArguments);
2780 return new GenericOpenTypeExpr (fne.Type, loc);
2784 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2786 if (!(fne is NamespaceExpression))
2790 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2791 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2792 mc.Module.Compiler.Report.Error (1980, Location,
2793 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2794 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2797 fne = new DynamicTypeExpr (loc);
2798 fne.ResolveAsType (mc);
2804 Error_TypeOrNamespaceNotFound (mc);
2808 bool IsPossibleTypeOrNamespace (IMemberContext mc)
2811 // Has to ignore static usings because we are looking for any member not just type
2814 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing | LookupMode.IgnoreStaticUsing, loc) != null;
2817 public bool IsPossibleType (IMemberContext mc)
2819 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
2822 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2824 int lookup_arity = Arity;
2825 bool errorMode = false;
2827 Block current_block = rc.CurrentBlock;
2828 INamedBlockVariable variable = null;
2829 bool variable_found = false;
2833 // Stage 1: binding to local variables or parameters
2835 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2837 if (current_block != null && lookup_arity == 0) {
2838 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2839 if (!variable.IsDeclared) {
2840 // We found local name in accessible block but it's not
2841 // initialized yet, maybe the user wanted to bind to something else
2843 variable_found = true;
2845 e = variable.CreateReferenceExpression (rc, loc);
2848 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2857 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2859 TypeSpec member_type = rc.CurrentType;
2860 for (; member_type != null; member_type = member_type.DeclaringType) {
2861 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2865 var me = e as MemberExpr;
2867 // The name matches a type, defer to ResolveAsTypeStep
2875 if (variable != null) {
2876 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2877 rc.Report.Error (844, loc,
2878 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2879 Name, me.GetSignatureForError ());
2883 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2884 // Leave it to overload resolution to report correct error
2886 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2887 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2891 // MemberLookup does not check accessors availability, this is actually needed for properties only
2893 var pe = me as PropertyExpr;
2896 // Break as there is no other overload available anyway
2897 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2898 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2901 pe.Getter = pe.PropertyInfo.Get;
2903 if (!pe.PropertyInfo.HasSet) {
2904 if (rc.HasSet (ResolveContext.Options.ConstructorScope) && pe.IsAutoPropertyAccess &&
2905 pe.PropertyInfo.DeclaringType == rc.CurrentType && pe.IsStatic == rc.IsStatic) {
2906 var p = (Property) pe.PropertyInfo.MemberDefinition;
2907 return new FieldExpr (p.BackingField, loc);
2910 variable_found = true;
2914 if (!pe.PropertyInfo.Set.IsAccessible (rc)) {
2915 variable_found = true;
2919 pe.Setter = pe.PropertyInfo.Set;
2924 // TODO: It's used by EventExpr -> FieldExpr transformation only
2925 // TODO: Should go to MemberAccess
2926 me = me.ResolveMemberAccess (rc, null, null);
2929 targs.Resolve (rc, false);
2930 me.SetTypeArguments (rc, targs);
2937 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2939 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2940 if (IsPossibleTypeOrNamespace (rc)) {
2941 return ResolveAsTypeOrNamespace (rc, false);
2945 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2948 targs.Resolve (rc, false);
2950 var me = expr as MemberExpr;
2952 me.SetTypeArguments (rc, targs);
2957 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2958 return new NameOf (this);
2961 if (variable_found) {
2962 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2965 var tparams = rc.CurrentTypeParameters;
2966 if (tparams != null) {
2967 if (tparams.Find (Name) != null) {
2968 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2973 var ct = rc.CurrentType;
2975 if (ct.MemberDefinition.TypeParametersCount > 0) {
2976 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2977 if (ctp.Name == Name) {
2978 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2984 ct = ct.DeclaringType;
2985 } while (ct != null);
2988 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2989 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2991 rc.Report.SymbolRelatedToPreviousError (e.Type);
2992 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2996 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2998 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2999 return ErrorExpression.Instance;
3003 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
3005 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
3006 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
3010 if (e is TypeExpr) {
3011 // TypeExpression does not have correct location
3012 if (e is TypeExpression)
3013 e = new TypeExpression (e.Type, loc);
3019 Error_NameDoesNotExist (rc);
3022 return ErrorExpression.Instance;
3025 if (rc.Module.Evaluator != null) {
3026 var fi = rc.Module.Evaluator.LookupField (Name);
3028 return new FieldExpr (fi.Item1, loc);
3036 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
3038 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
3043 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
3044 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
3048 if (right_side != null) {
3049 e = e.ResolveLValue (ec, right_side);
3057 public override object Accept (StructuralVisitor visitor)
3059 return visitor.Visit (this);
3064 /// Represents a namespace or a type. The name of the class was inspired by
3065 /// section 10.8.1 (Fully Qualified Names).
3067 public abstract class FullNamedExpression : Expression
3069 protected override void CloneTo (CloneContext clonectx, Expression target)
3071 // Do nothing, most unresolved type expressions cannot be
3072 // resolved to different type
3075 public override bool ContainsEmitWithAwait ()
3080 public override Expression CreateExpressionTree (ResolveContext ec)
3082 throw new NotSupportedException ("ET");
3085 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3088 // This is used to resolve the expression as a type, a null
3089 // value will be returned if the expression is not a type
3092 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3094 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3099 TypeExpr te = fne as TypeExpr;
3101 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3109 var dep = type.GetMissingDependencies ();
3111 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3114 if (type.Kind == MemberKind.Void) {
3115 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3119 // Obsolete checks cannot be done when resolving base context as they
3120 // require type dependencies to be set but we are in process of resolving them
3122 if (mc is ResolveContext) {
3123 var oa = type.GetAttributeObsolete ();
3124 if (oa != null && !mc.IsObsolete)
3125 AttributeTester.Report_ObsoleteMessage (oa, type.GetSignatureForError (), fne.Location, mc.Module.Compiler.Report);
3132 public override void Emit (EmitContext ec)
3134 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3135 GetSignatureForError ());
3140 /// Expression that evaluates to a type
3142 public abstract class TypeExpr : FullNamedExpression
3144 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3150 protected sealed override Expression DoResolve (ResolveContext ec)
3156 public override bool Equals (object obj)
3158 TypeExpr tobj = obj as TypeExpr;
3162 return Type == tobj.Type;
3165 public override int GetHashCode ()
3167 return Type.GetHashCode ();
3172 /// Fully resolved Expression that already evaluated to a type
3174 public class TypeExpression : TypeExpr
3176 public TypeExpression (TypeSpec t, Location l)
3179 eclass = ExprClass.Type;
3183 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3189 public class NamespaceExpression : FullNamedExpression
3191 readonly Namespace ns;
3193 public NamespaceExpression (Namespace ns, Location loc)
3196 this.Type = InternalType.Namespace;
3197 this.eclass = ExprClass.Namespace;
3201 public Namespace Namespace {
3207 protected override Expression DoResolve (ResolveContext rc)
3209 throw new NotImplementedException ();
3212 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3217 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3219 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3220 if (retval != null) {
3221 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3222 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3226 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3227 if (retval != null) {
3228 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3233 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3234 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3238 string assembly = null;
3239 string possible_name = Namespace.GetSignatureForError () + "." + name;
3241 // Only assembly unique name should be added
3242 switch (possible_name) {
3243 case "System.Drawing":
3244 case "System.Web.Services":
3247 case "System.Configuration":
3248 case "System.Data.Services":
3249 case "System.DirectoryServices":
3251 case "System.Net.Http":
3252 case "System.Numerics":
3253 case "System.Runtime.Caching":
3254 case "System.ServiceModel":
3255 case "System.Transactions":
3256 case "System.Web.Routing":
3257 case "System.Xml.Linq":
3259 assembly = possible_name;
3263 case "System.Linq.Expressions":
3264 assembly = "System.Core";
3267 case "System.Windows.Forms":
3268 case "System.Windows.Forms.Layout":
3269 assembly = "System.Windows.Forms";
3273 assembly = assembly == null ? "an" : "`" + assembly + "'";
3275 if (Namespace is GlobalRootNamespace) {
3276 ctx.Module.Compiler.Report.Error (400, loc,
3277 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3280 ctx.Module.Compiler.Report.Error (234, loc,
3281 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3282 name, GetSignatureForError (), assembly);
3286 public override string GetSignatureForError ()
3288 return ns.GetSignatureForError ();
3291 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3293 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3296 public override string ToString ()
3298 return Namespace.Name;
3303 /// This class denotes an expression which evaluates to a member
3304 /// of a struct or a class.
3306 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3308 protected bool conditional_access_receiver;
3311 // An instance expression associated with this member, if it's a
3312 // non-static member
3314 public Expression InstanceExpression;
3317 /// The name of this member.
3319 public abstract string Name {
3324 // When base.member is used
3326 public bool IsBase {
3327 get { return InstanceExpression is BaseThis; }
3331 /// Whether this is an instance member.
3333 public abstract bool IsInstance {
3338 /// Whether this is a static member.
3340 public abstract bool IsStatic {
3344 public abstract string KindName {
3348 public bool ConditionalAccess { get; set; }
3350 protected abstract TypeSpec DeclaringType {
3354 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3356 return InstanceExpression.Type;
3361 // Converts best base candidate for virtual method starting from QueriedBaseType
3363 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3366 // Only when base.member is used and method is virtual
3372 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3373 // means for base.member access we have to find the closest match after we found best candidate
3375 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3377 // The method could already be what we are looking for
3379 TypeSpec[] targs = null;
3380 if (method.DeclaringType != InstanceExpression.Type) {
3382 // Candidate can have inflated MVAR parameters and we need to find
3383 // base match for original definition not inflated parameter types
3385 var parameters = method.Parameters;
3386 if (method.Arity > 0) {
3387 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3388 var inflated = method.DeclaringType as InflatedTypeSpec;
3389 if (inflated != null) {
3390 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3394 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3395 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3396 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3397 if (base_override.IsGeneric)
3398 targs = method.TypeArguments;
3400 method = base_override;
3405 // When base access is used inside anonymous method/iterator/etc we need to
3406 // get back to the context of original type. We do it by emiting proxy
3407 // method in original class and rewriting base call to this compiler
3408 // generated method call which does the actual base invocation. This may
3409 // introduce redundant storey but with `this' only but it's tricky to avoid
3410 // at this stage as we don't know what expressions follow base
3412 // TODO: It's needed only when the method with base call is moved to a storey
3414 if (rc.CurrentAnonymousMethod != null) {
3415 if (targs == null && method.IsGeneric) {
3416 targs = method.TypeArguments;
3417 method = method.GetGenericMethodDefinition ();
3420 if (method.Parameters.HasArglist)
3421 throw new NotImplementedException ("__arglist base call proxy");
3423 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3425 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3426 // get/set member expressions second call would fail to proxy because left expression
3427 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3428 // FIXME: The async check is another hack but will probably fail with mutators
3429 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3430 InstanceExpression = new This (loc).Resolve (rc);
3434 method = method.MakeGenericMethod (rc, targs);
3438 // Only base will allow this invocation to happen.
3440 if (method.IsAbstract) {
3441 rc.Report.SymbolRelatedToPreviousError (method);
3442 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3448 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3450 if (InstanceExpression == null)
3453 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3454 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3455 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3460 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3462 if (InstanceExpression == null)
3465 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3468 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3470 var ct = rc.CurrentType;
3471 if (ct == qualifier)
3474 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3477 qualifier = qualifier.GetDefinition ();
3478 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3485 public override bool ContainsEmitWithAwait ()
3487 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3490 public override bool HasConditionalAccess ()
3492 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3495 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3498 type = type.GetDefinition ();
3500 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3503 type = type.DeclaringType;
3504 } while (type != null);
3509 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3511 if (InstanceExpression != null) {
3512 InstanceExpression = InstanceExpression.Resolve (rc);
3513 CheckProtectedMemberAccess (rc, member);
3516 if (member.MemberType.IsPointer) {
3517 if (rc.CurrentIterator != null) {
3518 UnsafeInsideIteratorError (rc, loc);
3519 } else if (!rc.IsUnsafe) {
3520 UnsafeError (rc, loc);
3524 var dep = member.GetMissingDependencies ();
3526 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3529 member.CheckObsoleteness (rc, loc);
3531 if (!(member is FieldSpec))
3532 member.MemberDefinition.SetIsUsed ();
3535 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3537 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3540 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3542 rc.Report.SymbolRelatedToPreviousError (member);
3543 rc.Report.Error (1540, loc,
3544 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3545 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3548 public override void FlowAnalysis (FlowAnalysisContext fc)
3550 if (InstanceExpression != null) {
3551 InstanceExpression.FlowAnalysis (fc);
3555 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3557 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
3558 conditional_access_receiver = true;
3562 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3564 if (!ResolveInstanceExpressionCore (rc, rhs))
3568 // Check intermediate value modification which won't have any effect
3570 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3571 var fexpr = InstanceExpression as FieldExpr;
3572 if (fexpr != null) {
3573 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3576 if (fexpr.IsStatic) {
3577 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3578 fexpr.GetSignatureForError ());
3580 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3581 fexpr.GetSignatureForError ());
3587 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3588 if (rc.CurrentInitializerVariable != null) {
3589 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3590 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3592 rc.Report.Error (1612, loc,
3593 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3594 InstanceExpression.GetSignatureForError ());
3600 var lvr = InstanceExpression as LocalVariableReference;
3603 if (!lvr.local_info.IsReadonly)
3606 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3607 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3614 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3617 if (InstanceExpression != null) {
3618 if (InstanceExpression is TypeExpr) {
3619 var t = InstanceExpression.Type;
3621 t.CheckObsoleteness (rc, loc);
3623 t = t.DeclaringType;
3624 } while (t != null);
3626 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3627 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3628 rc.Report.Error (176, loc,
3629 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3630 GetSignatureForError ());
3634 InstanceExpression = null;
3640 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3641 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3642 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3643 rc.Report.Error (236, loc,
3644 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3645 GetSignatureForError ());
3647 var fe = this as FieldExpr;
3648 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3649 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3650 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3652 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3656 rc.Report.Error (120, loc,
3657 "An object reference is required to access non-static member `{0}'",
3658 GetSignatureForError ());
3662 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3666 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3667 rc.Report.Error (38, loc,
3668 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3669 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3672 InstanceExpression = new This (loc).Resolve (rc);
3676 var me = InstanceExpression as MemberExpr;
3678 me.ResolveInstanceExpressionCore (rc, rhs);
3680 var fe = me as FieldExpr;
3681 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3682 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3683 rc.Report.Warning (1690, 1, loc,
3684 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3685 me.GetSignatureForError ());
3692 // Additional checks for l-value member access
3695 if (InstanceExpression is UnboxCast) {
3696 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3703 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3705 if (left != null && !ConditionalAccess && !ec.HasSet (ResolveContext.Options.NameOfScope) && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3706 ec.Report.Warning (1720, 1, left.Location,
3707 "Expression will always cause a `{0}'", "System.NullReferenceException");
3710 InstanceExpression = left;
3714 public virtual void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
3719 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3721 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3722 inst.Emit (ec, ConditionalAccess);
3724 if (prepare_for_load)
3725 ec.Emit (OpCodes.Dup);
3728 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3731 public class ExtensionMethodCandidates
3733 readonly NamespaceContainer container;
3734 readonly IList<MethodSpec> methods;
3736 readonly IMemberContext context;
3738 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3740 this.context = context;
3741 this.methods = methods;
3742 this.container = nsContainer;
3743 this.index = lookupIndex;
3746 public NamespaceContainer Container {
3752 public IMemberContext Context {
3758 public int LookupIndex {
3764 public IList<MethodSpec> Methods {
3772 // Represents a group of extension method candidates for whole namespace
3774 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3776 ExtensionMethodCandidates candidates;
3777 public Expression ExtensionExpression;
3779 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3780 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3782 this.candidates = candidates;
3783 this.ExtensionExpression = extensionExpr;
3786 public override bool IsStatic {
3787 get { return true; }
3791 // For extension methodgroup we are not looking for base members but parent
3792 // namespace extension methods
3794 public override IList<MemberSpec> GetBaseMembers (TypeSpec type)
3796 // TODO: candidates are null only when doing error reporting, that's
3797 // incorrect. We have to discover same extension methods in error mode
3798 if (candidates == null)
3801 int arity = type_arguments == null ? 0 : type_arguments.Count;
3803 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3804 if (candidates == null)
3807 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3810 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3813 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3815 // LAMESPEC: or implicit type parameter conversion
3817 return argType == extensionType ||
3818 TypeSpecComparer.IsEqual (argType, extensionType) ||
3819 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3820 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3823 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
3825 rc.Report.Error (8093, expr.Location, "An argument to nameof operator cannot be extension method group");
3828 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3830 // We are already here
3834 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3836 if (arguments == null)
3837 arguments = new Arguments (1);
3839 ExtensionExpression = ExtensionExpression.Resolve (ec);
3840 if (ExtensionExpression == null)
3843 var cand = candidates;
3844 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3845 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3846 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3848 // Restore candidates in case we are running in probing mode
3851 // Store resolved argument and restore original arguments
3853 // Clean-up modified arguments for error reporting
3854 arguments.RemoveAt (0);
3858 var me = ExtensionExpression as MemberExpr;
3860 me.ResolveInstanceExpression (ec, null);
3861 var fe = me as FieldExpr;
3863 fe.Spec.MemberDefinition.SetIsUsed ();
3866 InstanceExpression = null;
3870 #region IErrorHandler Members
3872 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3877 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3879 rc.Report.SymbolRelatedToPreviousError (best);
3882 rc.Report.Error (1929, loc,
3883 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3884 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3886 rc.Report.Error (1928, loc,
3887 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3888 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3894 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3899 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3908 /// MethodGroupExpr represents a group of method candidates which
3909 /// can be resolved to the best method overload
3911 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3913 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3915 protected IList<MemberSpec> Methods;
3916 MethodSpec best_candidate;
3917 TypeSpec best_candidate_return;
3918 protected TypeArguments type_arguments;
3920 SimpleName simple_name;
3921 protected TypeSpec queried_type;
3923 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3927 this.type = InternalType.MethodGroup;
3929 eclass = ExprClass.MethodGroup;
3930 queried_type = type;
3933 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3934 : this (new MemberSpec[] { m }, type, loc)
3940 public MethodSpec BestCandidate {
3942 return best_candidate;
3946 public TypeSpec BestCandidateReturnType {
3948 return best_candidate_return;
3952 public IList<MemberSpec> Candidates {
3958 protected override TypeSpec DeclaringType {
3960 return queried_type;
3964 public bool IsConditionallyExcluded {
3966 return Methods == Excluded;
3970 public override bool IsInstance {
3972 if (best_candidate != null)
3973 return !best_candidate.IsStatic;
3979 public override bool IsSideEffectFree {
3981 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3985 public override bool IsStatic {
3987 if (best_candidate != null)
3988 return best_candidate.IsStatic;
3994 public override string KindName {
3995 get { return "method"; }
3998 public override string Name {
4000 if (best_candidate != null)
4001 return best_candidate.Name;
4004 return Methods.First ().Name;
4011 // When best candidate is already know this factory can be used
4012 // to avoid expensive overload resolution to be called
4014 // NOTE: InstanceExpression has to be set manually
4016 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
4018 return new MethodGroupExpr (best, queriedType, loc) {
4019 best_candidate = best,
4020 best_candidate_return = best.ReturnType
4024 public override string GetSignatureForError ()
4026 if (best_candidate != null)
4027 return best_candidate.GetSignatureForError ();
4029 return Methods.First ().GetSignatureForError ();
4032 public override Expression CreateExpressionTree (ResolveContext ec)
4034 if (best_candidate == null) {
4035 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
4039 if (IsConditionallyExcluded)
4040 ec.Report.Error (765, loc,
4041 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
4043 if (ConditionalAccess)
4044 Error_NullShortCircuitInsideExpressionTree (ec);
4046 return new TypeOfMethod (best_candidate, loc);
4049 protected override Expression DoResolve (ResolveContext ec)
4051 this.eclass = ExprClass.MethodGroup;
4053 if (InstanceExpression != null) {
4054 InstanceExpression = InstanceExpression.Resolve (ec);
4055 if (InstanceExpression == null)
4062 public override void Emit (EmitContext ec)
4064 throw new NotSupportedException ();
4067 public override void EmitPrepare (EmitContext ec)
4069 InstanceExpression?.EmitPrepare (ec);
4072 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4074 var call = new CallEmitter ();
4075 call.InstanceExpression = InstanceExpression;
4076 call.ConditionalAccess = ConditionalAccess;
4079 call.EmitStatement (ec, best_candidate, arguments, loc);
4081 call.Emit (ec, best_candidate, arguments, loc);
4084 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4086 var ca = ec.ConditionalAccess;
4087 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4088 Statement = statement
4091 EmitCall (ec, arguments, statement);
4093 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4094 ec.ConditionalAccess = ca;
4097 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4099 if (target != InternalType.ErrorType) {
4100 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4101 Name, target.GetSignatureForError ());
4105 public bool HasAccessibleCandidate (ResolveContext rc)
4107 foreach (var candidate in Candidates) {
4108 if (candidate.IsAccessible (rc))
4115 public static bool IsExtensionMethodArgument (Expression expr)
4118 // LAMESPEC: No details about which expressions are not allowed
4120 return !(expr is TypeExpr) && !(expr is BaseThis);
4124 /// Find the Applicable Function Members (7.4.2.1)
4126 /// me: Method Group expression with the members to select.
4127 /// it might contain constructors or methods (or anything
4128 /// that maps to a method).
4130 /// Arguments: ArrayList containing resolved Argument objects.
4132 /// loc: The location if we want an error to be reported, or a Null
4133 /// location for "probing" purposes.
4135 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4136 /// that is the best match of me on Arguments.
4139 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4141 // TODO: causes issues with probing mode, remove explicit Kind check
4142 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4145 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4146 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4147 r.BaseMembersProvider = this;
4148 r.InstanceQualifier = this;
4151 if (cerrors != null)
4152 r.CustomErrors = cerrors;
4154 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4155 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4156 if (best_candidate == null) {
4157 if (!r.BestCandidateIsDynamic)
4160 if (simple_name != null && ec.IsStatic)
4161 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4166 // Overload resolver had to create a new method group, all checks bellow have already been executed
4167 if (r.BestCandidateNewMethodGroup != null)
4168 return r.BestCandidateNewMethodGroup;
4170 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4171 if (InstanceExpression != null) {
4172 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4173 InstanceExpression = null;
4175 if (simple_name != null && best_candidate.IsStatic) {
4176 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4179 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4183 ResolveInstanceExpression (ec, null);
4186 var base_override = CandidateToBaseOverride (ec, best_candidate);
4187 if (base_override == best_candidate) {
4188 best_candidate_return = r.BestCandidateReturnType;
4190 best_candidate = base_override;
4191 best_candidate_return = best_candidate.ReturnType;
4194 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4195 ConstraintChecker cc = new ConstraintChecker (ec);
4196 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4200 // Additional check for possible imported base override method which
4201 // could not be done during IsOverrideMethodBaseTypeAccessible
4203 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4204 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4205 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4206 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4209 // Speed up the check by not doing it on disallowed targets
4210 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4216 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4218 var fe = left as FieldExpr;
4221 // Using method-group on struct fields makes the struct assigned. I am not sure
4222 // why but that's what .net does
4224 fe.Spec.MemberDefinition.SetIsAssigned ();
4227 simple_name = original;
4228 return base.ResolveMemberAccess (ec, left, original);
4231 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
4233 if (!HasAccessibleCandidate (rc)) {
4234 ErrorIsInaccesible (rc, expr.GetSignatureForError (), loc);
4237 if (expr.HasTypeArguments) {
4238 rc.Report.Error (8084, expr.Location, "An argument to nameof operator cannot be method group with type arguments");
4242 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4244 type_arguments = ta;
4247 #region IBaseMembersProvider Members
4249 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec type)
4251 var baseType = type.BaseType;
4253 IList<MemberSpec> members = baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4255 if (members == null && !type.IsInterface) {
4256 var tps = queried_type as TypeParameterSpec;
4258 members = MemberCache.FindInterfaceMembers (tps, Methods [0].Name);
4264 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4266 if (queried_type == member.DeclaringType)
4269 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4270 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4274 // Extension methods lookup after ordinary methods candidates failed to apply
4276 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4278 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4281 if (!IsExtensionMethodArgument (InstanceExpression))
4284 int arity = type_arguments == null ? 0 : type_arguments.Count;
4285 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4286 if (methods == null)
4289 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4290 emg.SetTypeArguments (rc, type_arguments);
4291 emg.ConditionalAccess = ConditionalAccess;
4298 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4300 public ConstructorInstanceQualifier (TypeSpec type)
4303 InstanceType = type;
4306 public TypeSpec InstanceType { get; private set; }
4308 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4310 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4314 public struct OverloadResolver
4317 public enum Restrictions
4321 ProbingOnly = 1 << 1,
4322 CovariantDelegate = 1 << 2,
4323 NoBaseMembers = 1 << 3,
4324 BaseMembersIncluded = 1 << 4,
4325 GetEnumeratorLookup = 1 << 5
4328 public interface IBaseMembersProvider
4330 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4331 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4332 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4335 public interface IErrorHandler
4337 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4338 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4339 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4340 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4343 public interface IInstanceQualifier
4345 TypeSpec InstanceType { get; }
4346 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4349 sealed class NoBaseMembers : IBaseMembersProvider
4351 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4353 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4358 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4363 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4369 struct AmbiguousCandidate
4371 public readonly MemberSpec Member;
4372 public readonly bool Expanded;
4373 public readonly AParametersCollection Parameters;
4375 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4378 Parameters = parameters;
4379 Expanded = expanded;
4384 IList<MemberSpec> members;
4385 TypeArguments type_arguments;
4386 IBaseMembersProvider base_provider;
4387 IErrorHandler custom_errors;
4388 IInstanceQualifier instance_qualifier;
4389 Restrictions restrictions;
4390 MethodGroupExpr best_candidate_extension_group;
4391 TypeSpec best_candidate_return_type;
4393 SessionReportPrinter lambda_conv_msgs;
4395 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4396 : this (members, null, restrictions, loc)
4400 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4403 if (members == null || members.Count == 0)
4404 throw new ArgumentException ("empty members set");
4406 this.members = members;
4408 type_arguments = targs;
4409 this.restrictions = restrictions;
4410 if (IsDelegateInvoke)
4411 this.restrictions |= Restrictions.NoBaseMembers;
4413 base_provider = NoBaseMembers.Instance;
4418 public IBaseMembersProvider BaseMembersProvider {
4420 return base_provider;
4423 base_provider = value;
4427 public bool BestCandidateIsDynamic { get; set; }
4430 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4432 public MethodGroupExpr BestCandidateNewMethodGroup {
4434 return best_candidate_extension_group;
4439 // Return type can be different between best candidate and closest override
4441 public TypeSpec BestCandidateReturnType {
4443 return best_candidate_return_type;
4447 public IErrorHandler CustomErrors {
4449 return custom_errors;
4452 custom_errors = value;
4456 TypeSpec DelegateType {
4458 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4459 throw new InternalErrorException ("Not running in delegate mode", loc);
4461 return members [0].DeclaringType;
4465 public IInstanceQualifier InstanceQualifier {
4467 return instance_qualifier;
4470 instance_qualifier = value;
4474 bool IsProbingOnly {
4476 return (restrictions & Restrictions.ProbingOnly) != 0;
4480 bool IsDelegateInvoke {
4482 return (restrictions & Restrictions.DelegateInvoke) != 0;
4489 // 7.4.3.3 Better conversion from expression
4490 // Returns : 1 if a->p is better,
4491 // 2 if a->q is better,
4492 // 0 if neither is better
4494 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4496 TypeSpec argument_type = a.Type;
4499 // Exactly matching Expression phase
4503 // If argument is an anonymous function
4505 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4507 // p and q are delegate types or expression tree types
4509 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4510 if (q.MemberDefinition != p.MemberDefinition) {
4515 // Uwrap delegate from Expression<T>
4517 q = TypeManager.GetTypeArguments (q) [0];
4518 p = TypeManager.GetTypeArguments (p) [0];
4521 var p_m = Delegate.GetInvokeMethod (p);
4522 var q_m = Delegate.GetInvokeMethod (q);
4525 // With identical parameter lists
4527 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4535 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4537 if (p.Kind == MemberKind.Void) {
4538 return q.Kind != MemberKind.Void ? 2 : 0;
4542 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4544 if (q.Kind == MemberKind.Void) {
4545 return p.Kind != MemberKind.Void ? 1 : 0;
4548 var am = (AnonymousMethodExpression)a.Expr;
4551 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4552 // better conversion is performed between underlying types Y1 and Y2
4554 if (p.IsGenericTask || q.IsGenericTask) {
4555 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4556 q = q.TypeArguments [0];
4557 p = p.TypeArguments [0];
4563 // An inferred return type X exists for E in the context of the parameter list, and
4564 // an identity conversion exists from X to the return type of D
4566 var inferred_type = am.InferReturnType (ec, null, orig_q);
4567 if (inferred_type != null) {
4568 if (inferred_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4569 inferred_type = ec.BuiltinTypes.Object;
4571 if (inferred_type == p)
4574 if (inferred_type == q)
4580 if (argument_type == p)
4583 if (argument_type == q)
4586 return IsBetterConversionTarget (ec, p, q);
4589 static int IsBetterConversionTarget (ResolveContext rc, TypeSpec p, TypeSpec q)
4591 if ((p.Kind == MemberKind.Delegate || p.IsExpressionTreeType) && (q.Kind == MemberKind.Delegate || q.IsExpressionTreeType)) {
4593 if (p.Kind != MemberKind.Delegate) {
4594 p = TypeManager.GetTypeArguments (p) [0];
4597 if (q.Kind != MemberKind.Delegate) {
4598 q = TypeManager.GetTypeArguments (q) [0];
4601 var p_m = Delegate.GetInvokeMethod (p);
4602 var q_m = Delegate.GetInvokeMethod (q);
4608 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4610 if (p.Kind == MemberKind.Void) {
4611 return q.Kind != MemberKind.Void ? 2 : 0;
4615 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4617 if (q.Kind == MemberKind.Void) {
4618 return p.Kind != MemberKind.Void ? 1 : 0;
4621 return IsBetterConversionTarget (rc, p, q);
4624 if (p.IsGenericTask && q.IsGenericTask) {
4625 q = q.TypeArguments [0];
4626 p = p.TypeArguments [0];
4627 return IsBetterConversionTarget (rc, p, q);
4631 if (p.IsNullableType) {
4632 p = Nullable.NullableInfo.GetUnderlyingType (p);
4633 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (p))
4634 return BetterTypeConversionImplicitConversion (rc, p_orig, q);
4637 // Spec expects implicit conversion check between p and q, q and p
4638 // to be done before nullable unwrapping but that's expensive operation.
4640 // Extra manual tweak is needed because BetterTypeConversion works on
4648 if (q.IsNullableType) {
4649 q = Nullable.NullableInfo.GetUnderlyingType (q);
4650 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (q))
4651 return BetterTypeConversionImplicitConversion (rc, p_orig, q_orig);
4657 return BetterTypeConversion (rc, p, q);
4661 // 7.4.3.4 Better conversion from type
4663 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4665 if (p == null || q == null)
4666 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4668 switch (p.BuiltinType) {
4669 case BuiltinTypeSpec.Type.Int:
4670 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4673 case BuiltinTypeSpec.Type.Long:
4674 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4677 case BuiltinTypeSpec.Type.SByte:
4678 switch (q.BuiltinType) {
4679 case BuiltinTypeSpec.Type.Byte:
4680 case BuiltinTypeSpec.Type.UShort:
4681 case BuiltinTypeSpec.Type.UInt:
4682 case BuiltinTypeSpec.Type.ULong:
4686 case BuiltinTypeSpec.Type.Short:
4687 switch (q.BuiltinType) {
4688 case BuiltinTypeSpec.Type.UShort:
4689 case BuiltinTypeSpec.Type.UInt:
4690 case BuiltinTypeSpec.Type.ULong:
4694 case BuiltinTypeSpec.Type.Dynamic:
4695 // LAMESPEC: Dynamic conversions is not considered
4696 p = ec.Module.Compiler.BuiltinTypes.Object;
4700 switch (q.BuiltinType) {
4701 case BuiltinTypeSpec.Type.Int:
4702 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4705 case BuiltinTypeSpec.Type.Long:
4706 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4709 case BuiltinTypeSpec.Type.SByte:
4710 switch (p.BuiltinType) {
4711 case BuiltinTypeSpec.Type.Byte:
4712 case BuiltinTypeSpec.Type.UShort:
4713 case BuiltinTypeSpec.Type.UInt:
4714 case BuiltinTypeSpec.Type.ULong:
4718 case BuiltinTypeSpec.Type.Short:
4719 switch (p.BuiltinType) {
4720 case BuiltinTypeSpec.Type.UShort:
4721 case BuiltinTypeSpec.Type.UInt:
4722 case BuiltinTypeSpec.Type.ULong:
4726 case BuiltinTypeSpec.Type.Dynamic:
4727 // LAMESPEC: Dynamic conversions is not considered
4728 q = ec.Module.Compiler.BuiltinTypes.Object;
4732 return BetterTypeConversionImplicitConversion (ec, p, q);
4735 static int BetterTypeConversionImplicitConversion (ResolveContext rc, TypeSpec p, TypeSpec q)
4737 // TODO: this is expensive
4738 Expression p_tmp = new EmptyExpression (p);
4739 Expression q_tmp = new EmptyExpression (q);
4741 bool p_to_q = Convert.ImplicitConversionExists (rc, p_tmp, q);
4742 bool q_to_p = Convert.ImplicitConversionExists (rc, q_tmp, p);
4744 if (p_to_q && !q_to_p)
4747 if (q_to_p && !p_to_q)
4754 /// Determines "Better function" between candidate
4755 /// and the current best match
4758 /// Returns a boolean indicating :
4759 /// false if candidate ain't better
4760 /// true if candidate is better than the current best match
4762 bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4763 MemberSpec best, AParametersCollection bparam, bool best_params)
4765 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4766 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4768 int candidate_better_count = 0;
4769 int best_better_count = 0;
4771 bool are_equivalent = true;
4772 int args_count = args == null ? 0 : args.Count;
4776 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4779 // Default arguments are ignored for better decision
4780 if (a.IsDefaultArgument)
4784 // When comparing named argument the parameter type index has to be looked up
4785 // in original parameter set (override version for virtual members)
4787 NamedArgument na = a as NamedArgument;
4789 int idx = cparam.GetParameterIndexByName (na.Name);
4790 ct = candidate_pd.Types[idx];
4791 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4792 ct = TypeManager.GetElementType (ct);
4794 idx = bparam.GetParameterIndexByName (na.Name);
4795 bt = best_pd.Types[idx];
4796 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4797 bt = TypeManager.GetElementType (bt);
4799 ct = candidate_pd.Types[c_idx];
4800 bt = best_pd.Types[b_idx];
4802 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4803 ct = TypeManager.GetElementType (ct);
4807 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4808 bt = TypeManager.GetElementType (bt);
4813 if (TypeSpecComparer.IsEqual (ct, bt))
4816 are_equivalent = false;
4817 int result = BetterExpressionConversion (ec, a, ct, bt);
4819 // for each argument, the conversion to 'ct' should be no worse than
4820 // the conversion to 'bt'.
4823 // No optional parameters tie breaking rules for delegates overload resolution
4825 if ((restrictions & Restrictions.CovariantDelegate) != 0)
4828 ++best_better_count;
4832 // for at least one argument, the conversion to 'ct' should be better than
4833 // the conversion to 'bt'.
4835 ++candidate_better_count;
4838 if (candidate_better_count != 0 && best_better_count == 0)
4841 if (best_better_count > 0 && candidate_better_count == 0)
4845 // LAMESPEC: Tie-breaking rules for not equivalent parameter types
4847 if (!are_equivalent) {
4848 while (j < args_count && !args [j++].IsDefaultArgument) ;
4851 // A candidate with no default parameters is still better when there
4852 // is no better expression conversion and does not have more parameters
4854 if (candidate_pd.Count < best_pd.Count) {
4855 if (candidate_params)
4858 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue)
4861 if (best_pd.FixedParameters [j].HasDefaultValue)
4864 } else if (candidate_pd.Count == best_pd.Count) {
4865 if (candidate_params)
4868 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.FixedParameters [j - 1].HasDefaultValue)
4871 if (candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.HasParams)
4879 // If candidate is applicable in its normal form and best has a params array and is applicable
4880 // only in its expanded form, then candidate is better
4882 if (candidate_params != best_params)
4883 return !candidate_params;
4886 // We have not reached end of parameters list due to params or used default parameters
4888 bool defaults_ambiguity = false;
4889 while (j < candidate_pd.Count && j < best_pd.Count) {
4890 var cand_param = candidate_pd.FixedParameters [j];
4891 var best_param = best_pd.FixedParameters [j];
4893 if (cand_param.HasDefaultValue != best_param.HasDefaultValue && (!candidate_pd.HasParams || !best_pd.HasParams))
4894 return cand_param.HasDefaultValue;
4896 defaults_ambiguity = true;
4897 if (candidate_pd.Count == best_pd.Count) {
4901 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4902 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4904 if (cand_param.HasDefaultValue) {
4913 // Neither is better when not all arguments are provided
4915 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4916 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4917 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4922 if (candidate_pd.Count != best_pd.Count) {
4923 if (defaults_ambiguity && best_pd.Count - 1 == j)
4924 return best_pd.HasParams;
4926 return candidate_pd.Count < best_pd.Count;
4930 // One is a non-generic method and second is a generic method, then non-generic is better
4932 if (best.IsGeneric != candidate.IsGeneric)
4933 return best.IsGeneric;
4936 // Both methods have the same number of parameters, and the parameters have equal types
4937 // Pick the "more specific" signature using rules over original (non-inflated) types
4939 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4940 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4942 bool specific_at_least_once = false;
4943 for (j = 0; j < args_count; ++j) {
4944 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4946 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4947 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4949 ct = candidate_def_pd.Types[j];
4950 bt = best_def_pd.Types[j];
4955 TypeSpec specific = MoreSpecific (ct, bt);
4959 specific_at_least_once = true;
4962 if (specific_at_least_once)
4968 static bool CheckInflatedArguments (MethodSpec ms)
4970 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4973 // Setup constraint checker for probing only
4974 ConstraintChecker cc = new ConstraintChecker (null);
4976 var mp = ms.Parameters.Types;
4977 for (int i = 0; i < mp.Length; ++i) {
4978 var type = mp[i] as InflatedTypeSpec;
4982 var targs = type.TypeArguments;
4983 if (targs.Length == 0)
4986 // TODO: Checking inflated MVAR arguments should be enough
4987 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4994 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4996 rc.Report.Error (1729, loc,
4997 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4998 type.GetSignatureForError (), argCount.ToString ());
5002 // Determines if the candidate method is applicable to the given set of arguments
5003 // There could be two different set of parameters for same candidate where one
5004 // is the closest override for default values and named arguments checks and second
5005 // one being the virtual base for the parameter types and modifiers.
5007 // A return value rates candidate method compatibility,
5009 // 0 = the best, int.MaxValue = the worst
5011 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, bool errorMode)
5014 // Each step has allocated 10 values, it can overflow for
5015 // more than 10 arguments but that's ok as it's used for
5016 // better error reporting only
5018 const int ArgumentCountMismatch = 1000000000;
5019 const int NamedArgumentsMismatch = 100000000;
5020 const int DefaultArgumentMismatch = 10000000;
5021 const int UnexpectedTypeArguments = 1000000;
5022 const int TypeArgumentsMismatch = 100000;
5023 const int InflatedTypesMismatch = 10000;
5025 // Parameters of most-derived type used mainly for named and optional parameters
5026 var pd = pm.Parameters;
5028 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
5029 // params modifier instead of most-derived type
5030 var cpd = ((IParametersMember) candidate).Parameters;
5031 int param_count = pd.Count;
5032 int optional_count = 0;
5034 Arguments orig_args = arguments;
5036 if (arg_count != param_count) {
5038 // No arguments expansion when doing exact match for delegates
5040 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
5041 for (int i = 0; i < pd.Count; ++i) {
5042 if (pd.FixedParameters[i].HasDefaultValue) {
5043 optional_count = pd.Count - i;
5049 if (optional_count != 0) {
5050 // Readjust expected number when params used
5051 if (cpd.HasParams) {
5053 if (arg_count < param_count)
5055 } else if (arg_count > param_count) {
5056 int args_gap = System.Math.Abs (arg_count - param_count);
5057 return ArgumentCountMismatch + args_gap;
5058 } else if (arg_count < param_count - optional_count) {
5059 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
5060 return ArgumentCountMismatch + args_gap;
5062 } else if (arg_count != param_count) {
5063 int args_gap = System.Math.Abs (arg_count - param_count);
5065 return ArgumentCountMismatch + args_gap;
5066 if (arg_count < param_count - 1)
5067 return ArgumentCountMismatch + args_gap;
5070 // Resize to fit optional arguments
5071 if (optional_count != 0) {
5072 if (arguments == null) {
5073 arguments = new Arguments (optional_count);
5075 // Have to create a new container, so the next run can do same
5076 var resized = new Arguments (param_count);
5077 resized.AddRange (arguments);
5078 arguments = resized;
5081 for (int i = arg_count; i < param_count; ++i)
5082 arguments.Add (null);
5086 if (arg_count > 0) {
5088 // Shuffle named arguments to the right positions if there are any
5090 if (arguments[arg_count - 1] is NamedArgument) {
5091 arg_count = arguments.Count;
5093 for (int i = 0; i < arg_count; ++i) {
5094 bool arg_moved = false;
5096 NamedArgument na = arguments[i] as NamedArgument;
5100 int index = pd.GetParameterIndexByName (na.Name);
5102 // Named parameter not found
5104 return NamedArgumentsMismatch - i;
5106 // already reordered
5111 if (index >= param_count) {
5112 // When using parameters which should not be available to the user
5113 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
5116 arguments.Add (null);
5120 if (index == arg_count)
5121 return NamedArgumentsMismatch - i - 1;
5123 temp = arguments [index];
5125 // The slot has been taken by positional argument
5126 if (temp != null && !(temp is NamedArgument))
5127 return NamedArgumentsMismatch - i - 1;
5131 arguments = arguments.MarkOrderedArgument (na);
5135 if (arguments == orig_args) {
5136 arguments = new Arguments (orig_args.Count);
5137 arguments.AddRange (orig_args);
5140 arguments[index] = arguments[i];
5141 arguments[i] = temp;
5148 arg_count = arguments.Count;
5150 } else if (arguments != null) {
5151 arg_count = arguments.Count;
5155 // Don't do any expensive checks when the candidate cannot succeed
5157 if (arg_count != param_count && !cpd.HasParams)
5158 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5160 var dep = candidate.GetMissingDependencies ();
5162 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5167 // 1. Handle generic method using type arguments when specified or type inference
5170 var ms = candidate as MethodSpec;
5171 if (ms != null && ms.IsGeneric) {
5172 if (type_arguments != null) {
5173 var g_args_count = ms.Arity;
5174 if (g_args_count != type_arguments.Count)
5175 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5177 if (type_arguments.Arguments != null)
5178 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5181 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5182 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5183 // candidate was found use the set to report more details about what was wrong with lambda body.
5184 // The general idea is to distinguish between code errors and errors caused by
5185 // trial-and-error type inference
5187 if (lambda_conv_msgs == null) {
5188 for (int i = 0; i < arg_count; i++) {
5189 Argument a = arguments[i];
5193 var am = a.Expr as AnonymousMethodExpression;
5195 if (lambda_conv_msgs == null)
5196 lambda_conv_msgs = new SessionReportPrinter ();
5198 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5203 var ti = new TypeInference (arguments);
5204 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5207 return TypeArgumentsMismatch - ti.InferenceScore;
5210 // Clear any error messages when the result was success
5212 if (lambda_conv_msgs != null)
5213 lambda_conv_msgs.ClearSession ();
5215 if (i_args.Length != 0) {
5217 for (int i = 0; i < i_args.Length; ++i) {
5218 var ta = i_args [i];
5219 if (!ta.IsAccessible (ec))
5220 return TypeArgumentsMismatch - i;
5224 ms = ms.MakeGenericMethod (ec, i_args);
5229 // Type arguments constraints have to match for the method to be applicable
5231 if (!CheckInflatedArguments (ms)) {
5233 return InflatedTypesMismatch;
5237 // We have a generic return type and at same time the method is override which
5238 // means we have to also inflate override return type in case the candidate is
5239 // best candidate and override return type is different to base return type.
5241 // virtual Foo<T, object> with override Foo<T, dynamic>
5243 if (candidate != pm) {
5244 MethodSpec override_ms = (MethodSpec) pm;
5245 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5246 returnType = inflator.Inflate (returnType);
5248 returnType = ms.ReturnType;
5255 if (type_arguments != null)
5256 return UnexpectedTypeArguments;
5262 // 2. Each argument has to be implicitly convertible to method parameter
5264 Parameter.Modifier p_mod = 0;
5267 for (int i = 0; i < arg_count; i++) {
5268 Argument a = arguments[i];
5270 var fp = pd.FixedParameters[i];
5271 if (!fp.HasDefaultValue) {
5272 arguments = orig_args;
5273 return arg_count * 2 + 2;
5277 // Get the default value expression, we can use the same expression
5278 // if the type matches
5280 Expression e = fp.DefaultValue;
5282 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5284 // Restore for possible error reporting
5285 for (int ii = i; ii < arg_count; ++ii)
5286 arguments.RemoveAt (i);
5288 return (arg_count - i) * 2 + 1;
5292 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5294 // LAMESPEC: Attributes can be mixed together with build-in priority
5296 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5297 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5298 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5299 e = new StringLiteral (ec.BuiltinTypes, loc.SourceFile.GetFullPathName (ec.Module.Compiler.Settings.PathMap), loc);
5300 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5301 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5305 arguments[i] = new Argument (e, Argument.AType.Default);
5309 if (p_mod != Parameter.Modifier.PARAMS) {
5310 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5312 } else if (!params_expanded_form) {
5313 params_expanded_form = true;
5314 pt = ((ElementTypeSpec) pt).Element;
5320 if (!params_expanded_form) {
5321 if (a.IsExtensionType) {
5322 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5327 score = IsArgumentCompatible (ec, a, p_mod, pt);
5330 dynamicArgument = true;
5335 // It can be applicable in expanded form (when not doing exact match like for delegates)
5337 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5338 if (!params_expanded_form) {
5339 pt = ((ElementTypeSpec) pt).Element;
5343 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5346 params_expanded_form = true;
5347 dynamicArgument = true;
5348 } else if (score == 0 || arg_count > pd.Count) {
5349 params_expanded_form = true;
5354 if (params_expanded_form)
5356 return (arg_count - i) * 2 + score;
5361 // Restore original arguments for dynamic binder to keep the intention of original source code
5363 if (dynamicArgument)
5364 arguments = orig_args;
5369 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5371 if (e is Constant && e.Type == ptype)
5375 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5377 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5378 e = new MemberAccess (new MemberAccess (new MemberAccess (
5379 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5380 } else if (e is Constant) {
5382 // Handles int to int? conversions, DefaultParameterValue check
5384 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5388 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5391 return e.Resolve (ec);
5395 // Tests argument compatibility with the parameter
5396 // The possible return values are
5398 // 1 - modifier mismatch
5399 // 2 - type mismatch
5400 // -1 - dynamic binding required
5402 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5405 // Types have to be identical when ref or out modifer
5406 // is used and argument is not of dynamic type
5408 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5409 var arg_type = argument.Type;
5411 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5413 // Using dynamic for ref/out parameter can still succeed at runtime
5415 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5421 if (arg_type != parameter) {
5422 if (arg_type == InternalType.VarOutType)
5425 var ref_arg_type = arg_type as ReferenceContainer;
5426 if (ref_arg_type != null) {
5427 arg_type = ref_arg_type.Element;
5431 // Do full equality check after quick path
5433 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5435 // Using dynamic for ref/out parameter can still succeed at runtime
5437 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5445 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5449 // Use implicit conversion in all modes to return same candidates when the expression
5450 // is used as argument or delegate conversion
5452 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5453 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5460 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5462 if (p.IsGenericParameter != q.IsGenericParameter)
5463 return p.IsGenericParameter ? q : p;
5465 var ac_p = p as ArrayContainer;
5467 var ac_q = q as ArrayContainer;
5471 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5472 if (specific == ac_p.Element)
5474 if (specific == ac_q.Element)
5480 if (p.IsGeneric && q.IsGeneric) {
5481 var pargs = p.TypeArguments;
5482 var qargs = q.TypeArguments;
5484 bool p_specific_at_least_once = false;
5485 bool q_specific_at_least_once = false;
5487 for (int i = 0; i < pargs.Length; i++) {
5488 TypeSpec specific = MoreSpecific (pargs [i], qargs [i]);
5489 if (specific == pargs [i])
5490 p_specific_at_least_once = true;
5491 if (specific == qargs [i])
5492 q_specific_at_least_once = true;
5495 if (p_specific_at_least_once && !q_specific_at_least_once)
5497 if (!p_specific_at_least_once && q_specific_at_least_once)
5505 // Find the best method from candidate list
5507 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5509 List<AmbiguousCandidate> ambiguous_candidates = null;
5511 MemberSpec best_candidate;
5512 Arguments best_candidate_args = null;
5513 bool best_candidate_params = false;
5514 bool best_candidate_dynamic = false;
5515 int best_candidate_rate;
5516 IParametersMember best_parameter_member = null;
5518 int args_count = args != null ? args.Count : 0;
5520 Arguments candidate_args = args;
5521 bool error_mode = false;
5522 MemberSpec invocable_member = null;
5523 int applicable_candidates = 0;
5526 best_candidate = null;
5527 best_candidate_rate = int.MaxValue;
5529 var type_members = members;
5531 for (int i = 0; i < type_members.Count; ++i) {
5532 var member = type_members[i];
5535 // Methods in a base class are not candidates if any method in a derived
5536 // class is applicable
5538 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5542 if (!member.IsAccessible (rc))
5545 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5548 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5549 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5554 IParametersMember pm = member as IParametersMember;
5557 // Will use it later to report ambiguity between best method and invocable member
5559 if (Invocation.IsMemberInvocable (member))
5560 invocable_member = member;
5566 // Overload resolution is looking for base member but using parameter names
5567 // and default values from the closest member. That means to do expensive lookup
5568 // for the closest override for virtual or abstract members
5570 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5571 var override_params = base_provider.GetOverrideMemberParameters (member);
5572 if (override_params != null)
5573 pm = override_params;
5577 // Check if the member candidate is applicable
5579 bool params_expanded_form = false;
5580 bool dynamic_argument = false;
5581 TypeSpec rt = pm.MemberType;
5582 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5584 if (lambda_conv_msgs != null)
5585 lambda_conv_msgs.EndSession ();
5588 // How does it score compare to others
5590 if (candidate_rate < best_candidate_rate) {
5592 // Fatal error (missing dependency), cannot continue
5593 if (candidate_rate < 0)
5596 applicable_candidates = 1;
5597 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5598 // Only parameterless methods are considered
5600 best_candidate_rate = candidate_rate;
5601 best_candidate = member;
5602 best_candidate_args = candidate_args;
5603 best_candidate_params = params_expanded_form;
5604 best_candidate_dynamic = dynamic_argument;
5605 best_parameter_member = pm;
5606 best_candidate_return_type = rt;
5608 } else if (candidate_rate == 0) {
5610 // The member look is done per type for most operations but sometimes
5611 // it's not possible like for binary operators overload because they
5612 // are unioned between 2 sides
5614 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5615 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5619 ++applicable_candidates;
5621 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5623 // We pack all interface members into top level type which makes the overload resolution
5624 // more complicated for interfaces. We compensate it by removing methods with same
5625 // signature when building the cache hence this path should not really be hit often
5628 // interface IA { void Foo (int arg); }
5629 // interface IB : IA { void Foo (params int[] args); }
5631 // IB::Foo is the best overload when calling IB.Foo (1)
5634 if (ambiguous_candidates != null) {
5635 foreach (var amb_cand in ambiguous_candidates) {
5636 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5645 ambiguous_candidates = null;
5648 // Is the new candidate better
5649 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5653 best_candidate = member;
5654 best_candidate_args = candidate_args;
5655 best_candidate_params = params_expanded_form;
5656 best_candidate_dynamic = dynamic_argument;
5657 best_parameter_member = pm;
5658 best_candidate_return_type = rt;
5660 // It's not better but any other found later could be but we are not sure yet
5661 if (ambiguous_candidates == null)
5662 ambiguous_candidates = new List<AmbiguousCandidate> ();
5664 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5668 // Restore expanded arguments
5669 candidate_args = args;
5671 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType)) != null);
5674 // We've found exact match
5676 if (best_candidate_rate == 0)
5680 // Try extension methods lookup when no ordinary method match was found and provider enables it
5683 var emg = base_provider.LookupExtensionMethod (rc);
5685 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5687 best_candidate_extension_group = emg;
5688 return (T) (MemberSpec) emg.BestCandidate;
5693 // Don't run expensive error reporting mode for probing
5700 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5703 lambda_conv_msgs = null;
5708 // No best member match found, report an error
5710 if (best_candidate_rate != 0 || error_mode) {
5711 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5715 if (best_candidate_dynamic) {
5716 if (args[0].IsExtensionType) {
5717 rc.Report.Error (1973, loc,
5718 "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",
5719 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5723 // Check type constraints only when explicit type arguments are used
5725 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5726 MethodSpec bc = best_candidate as MethodSpec;
5727 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5728 ConstraintChecker cc = new ConstraintChecker (rc);
5729 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5733 BestCandidateIsDynamic = true;
5738 // These flags indicates we are running delegate probing conversion. No need to
5739 // do more expensive checks
5741 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5742 return (T) best_candidate;
5744 if (ambiguous_candidates != null) {
5746 // Now check that there are no ambiguities i.e the selected method
5747 // should be better than all the others
5749 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5750 var candidate = ambiguous_candidates [ix];
5752 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5753 var ambiguous = candidate.Member;
5754 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5755 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5756 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5757 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5758 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5761 return (T) best_candidate;
5766 if (invocable_member != null && !IsProbingOnly) {
5767 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5768 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5769 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5770 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5774 // And now check if the arguments are all
5775 // compatible, perform conversions if
5776 // necessary etc. and return if everything is
5779 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5782 if (best_candidate == null)
5786 // Don't run possibly expensive checks in probing mode
5788 if (!IsProbingOnly && !rc.IsInProbingMode) {
5790 // Check ObsoleteAttribute on the best method
5792 best_candidate.CheckObsoleteness (rc, loc);
5794 best_candidate.MemberDefinition.SetIsUsed ();
5797 args = best_candidate_args;
5798 return (T) best_candidate;
5801 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5803 return ResolveMember<MethodSpec> (rc, ref args);
5806 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5807 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5809 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5812 if (a.Type == InternalType.ErrorType)
5815 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5816 ec.Report.SymbolRelatedToPreviousError (method);
5817 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5818 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5819 TypeManager.CSharpSignature (method));
5822 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5823 TypeManager.CSharpSignature (method));
5824 } else if (IsDelegateInvoke) {
5825 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5826 DelegateType.GetSignatureForError ());
5828 ec.Report.SymbolRelatedToPreviousError (method);
5829 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5830 method.GetSignatureForError ());
5833 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5835 string index = (idx + 1).ToString ();
5836 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5837 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5838 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5839 index, Parameter.GetModifierSignature (a.Modifier));
5841 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5842 index, Parameter.GetModifierSignature (mod));
5844 string p1 = a.GetSignatureForError ();
5845 string p2 = paramType.GetSignatureForError ();
5848 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5849 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5852 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5853 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5854 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5857 ec.Report.Error (1503, a.Expr.Location,
5858 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5863 // We have failed to find exact match so we return error info about the closest match
5865 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5867 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5868 int arg_count = args == null ? 0 : args.Count;
5870 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5871 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5872 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5876 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5881 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5882 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5883 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5887 // For candidates which match on parameters count report more details about incorrect arguments
5890 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5891 // Reject any inaccessible member
5892 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5893 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5894 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5898 var ms = best_candidate as MethodSpec;
5899 if (ms != null && ms.IsGeneric) {
5900 bool constr_ok = true;
5901 if (ms.TypeArguments != null)
5902 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5904 if (ta_count == 0 && ms.TypeArguments == null) {
5905 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5909 rc.Report.Error (411, loc,
5910 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5911 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5918 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5924 // We failed to find any method with correct argument count, report best candidate
5926 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5929 if (best_candidate.Kind == MemberKind.Constructor) {
5930 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5931 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5932 } else if (IsDelegateInvoke) {
5933 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5934 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5935 DelegateType.GetSignatureForError (), arg_count.ToString ());
5937 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5938 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5939 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5940 name, arg_count.ToString ());
5944 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5946 var p = ((IParametersMember)best_candidate).Parameters;
5951 for (int i = p.Count - 1; i != 0; --i) {
5952 var fp = p.FixedParameters [i];
5953 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5963 foreach (var arg in args) {
5964 var na = arg as NamedArgument;
5968 if (na.Name == name) {
5977 return args.Count + 1 == pm.Parameters.Count;
5980 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5982 var pd = pm.Parameters;
5983 var cpd = ((IParametersMember) member).Parameters;
5984 var ptypes = cpd.Types;
5986 Parameter.Modifier p_mod = 0;
5988 int a_idx = 0, a_pos = 0;
5990 ArrayInitializer params_initializers = null;
5991 bool has_unsafe_arg = pm.MemberType.IsPointer;
5992 int arg_count = args == null ? 0 : args.Count;
5994 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5999 if (p_mod != Parameter.Modifier.PARAMS) {
6000 p_mod = cpd.FixedParameters [a_idx].ModFlags;
6001 pt = ptypes [a_idx];
6002 has_unsafe_arg |= pt.IsPointer;
6004 if (p_mod == Parameter.Modifier.PARAMS) {
6005 if (chose_params_expanded) {
6006 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
6007 pt = TypeManager.GetElementType (pt);
6013 // Types have to be identical when ref or out modifer is used
6015 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
6016 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
6019 var arg_type = a.Type;
6023 if (arg_type == InternalType.VarOutType) {
6025 // Set underlying variable type based on parameter type
6027 ((DeclarationExpression)a.Expr).Variable.Type = pt;
6031 var ref_arg_type = arg_type as ReferenceContainer;
6032 if (ref_arg_type != null) {
6033 if (ref_arg_type.Element != pt)
6039 if (!TypeSpecComparer.IsEqual (arg_type, pt))
6043 NamedArgument na = a as NamedArgument;
6045 int name_index = pd.GetParameterIndexByName (na.Name);
6046 if (name_index < 0 || name_index >= pd.Count) {
6047 if (IsDelegateInvoke) {
6048 ec.Report.SymbolRelatedToPreviousError (DelegateType);
6049 ec.Report.Error (1746, na.Location,
6050 "The delegate `{0}' does not contain a parameter named `{1}'",
6051 DelegateType.GetSignatureForError (), na.Name);
6053 ec.Report.SymbolRelatedToPreviousError (member);
6054 ec.Report.Error (1739, na.Location,
6055 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
6056 TypeManager.CSharpSignature (member), na.Name);
6058 } else if (args[name_index] != a && args[name_index] != null) {
6059 if (IsDelegateInvoke)
6060 ec.Report.SymbolRelatedToPreviousError (DelegateType);
6062 ec.Report.SymbolRelatedToPreviousError (member);
6064 ec.Report.Error (1744, na.Location,
6065 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
6070 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6073 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
6074 if (a.IsExtensionType) {
6075 // TODO: Should report better message type, something similar to CS1928/1929 instead of
6076 // CS1061 but that still better than confusing CS0123
6077 var ma = new MemberAccess (a.Expr, member.Name, loc);
6078 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
6080 custom_errors.NoArgumentMatch (ec, member);
6086 if (a.IsExtensionType) {
6087 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
6090 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
6092 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
6095 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
6102 // Convert params arguments to an array initializer
6104 if (params_initializers != null) {
6105 // we choose to use 'a.Expr' rather than 'conv' so that
6106 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
6107 params_initializers.Add (a.Expr);
6108 args.RemoveAt (a_idx--);
6114 // Update the argument with the implicit conversion
6118 if (a_idx != arg_count) {
6120 // Convert all var out argument to error type for less confusing error reporting
6121 // when no matching overload is found
6123 for (; a_idx < arg_count; a_idx++) {
6124 var arg = args [a_idx];
6128 if (arg.Type == InternalType.VarOutType) {
6129 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
6133 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
6138 // Fill not provided arguments required by params modifier
6140 if (params_initializers == null && arg_count + 1 == pd.Count) {
6142 args = new Arguments (1);
6144 pt = ptypes[pd.Count - 1];
6145 pt = TypeManager.GetElementType (pt);
6146 has_unsafe_arg |= pt.IsPointer;
6147 params_initializers = new ArrayInitializer (0, loc);
6151 // Append an array argument with all params arguments
6153 if (params_initializers != null) {
6154 args.Add (new Argument (
6155 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
6159 if (has_unsafe_arg) {
6160 if (ec.CurrentIterator != null) {
6161 Expression.UnsafeInsideIteratorError (ec, loc);
6162 } else if (!ec.IsUnsafe) {
6163 Expression.UnsafeError (ec, loc);
6168 // We could infer inaccesible type arguments
6170 if (type_arguments == null && member.IsGeneric) {
6171 var ms = (MethodSpec) member;
6172 foreach (var ta in ms.TypeArguments) {
6173 if (!ta.IsAccessible (ec)) {
6174 ec.Report.SymbolRelatedToPreviousError (ta);
6175 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6185 public class ConstantExpr : MemberExpr
6187 readonly ConstSpec constant;
6189 public ConstantExpr (ConstSpec constant, Location loc)
6191 this.constant = constant;
6195 public override string Name {
6196 get { throw new NotImplementedException (); }
6199 public override string KindName {
6200 get { return "constant"; }
6203 public override bool IsInstance {
6204 get { return !IsStatic; }
6207 public override bool IsStatic {
6208 get { return true; }
6211 protected override TypeSpec DeclaringType {
6212 get { return constant.DeclaringType; }
6215 public override Expression CreateExpressionTree (ResolveContext ec)
6217 throw new NotSupportedException ("ET");
6220 protected override Expression DoResolve (ResolveContext rc)
6222 ResolveInstanceExpression (rc, null);
6223 DoBestMemberChecks (rc, constant);
6225 if (rc.HasSet (ResolveContext.Options.NameOfScope)) {
6226 eclass = ExprClass.Value;
6227 type = constant.MemberType;
6231 var c = constant.GetConstant (rc);
6233 // Creates reference expression to the constant value
6234 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6237 public override void Emit (EmitContext ec)
6239 throw new NotSupportedException ();
6242 public override string GetSignatureForError ()
6244 return constant.GetSignatureForError ();
6247 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
6249 constant.CheckObsoleteness (rc, expr.Location);
6252 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6254 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6259 // Fully resolved expression that references a Field
6261 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6263 protected FieldSpec spec;
6264 VariableInfo variable_info;
6266 LocalTemporary temp;
6269 protected FieldExpr (Location l)
6274 public FieldExpr (FieldSpec spec, Location loc)
6279 type = spec.MemberType;
6282 public FieldExpr (FieldBase fi, Location l)
6289 public override string Name {
6295 public bool IsHoisted {
6297 IVariableReference hv = InstanceExpression as IVariableReference;
6298 return hv != null && hv.IsHoisted;
6302 public override bool IsInstance {
6304 return !spec.IsStatic;
6308 public override bool IsStatic {
6310 return spec.IsStatic;
6314 public override string KindName {
6315 get { return "field"; }
6318 public FieldSpec Spec {
6324 protected override TypeSpec DeclaringType {
6326 return spec.DeclaringType;
6330 public VariableInfo VariableInfo {
6332 return variable_info;
6338 public override string GetSignatureForError ()
6340 return spec.GetSignatureForError ();
6343 public bool IsMarshalByRefAccess (ResolveContext rc)
6345 // Checks possible ldflda of field access expression
6346 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6347 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6348 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6351 public void SetHasAddressTaken ()
6353 IVariableReference vr = InstanceExpression as IVariableReference;
6355 vr.SetHasAddressTaken ();
6359 protected override void CloneTo (CloneContext clonectx, Expression target)
6361 var t = (FieldExpr) target;
6363 if (InstanceExpression != null)
6364 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6367 public override Expression CreateExpressionTree (ResolveContext ec)
6369 if (ConditionalAccess) {
6370 Error_NullShortCircuitInsideExpressionTree (ec);
6373 return CreateExpressionTree (ec, true);
6376 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6379 Expression instance;
6381 if (InstanceExpression == null) {
6382 instance = new NullLiteral (loc);
6383 } else if (convertInstance) {
6384 instance = InstanceExpression.CreateExpressionTree (ec);
6386 args = new Arguments (1);
6387 args.Add (new Argument (InstanceExpression));
6388 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6391 args = Arguments.CreateForExpressionTree (ec, null,
6393 CreateTypeOfExpression ());
6395 return CreateExpressionFactoryCall (ec, "Field", args);
6398 public Expression CreateTypeOfExpression ()
6400 return new TypeOfField (spec, loc);
6403 protected override Expression DoResolve (ResolveContext ec)
6405 spec.MemberDefinition.SetIsUsed ();
6407 return DoResolve (ec, null);
6410 Expression DoResolve (ResolveContext ec, Expression rhs)
6412 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6415 ResolveConditionalAccessReceiver (ec);
6417 if (ResolveInstanceExpression (ec, rhs)) {
6418 // Resolve the field's instance expression while flow analysis is turned
6419 // off: when accessing a field "a.b", we must check whether the field
6420 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6422 if (lvalue_instance) {
6423 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6425 Expression right_side =
6426 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6428 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6430 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6433 if (InstanceExpression == null)
6437 DoBestMemberChecks (ec, spec);
6439 if (conditional_access_receiver)
6440 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
6443 var fb = spec as FixedFieldSpec;
6444 IVariableReference var = InstanceExpression as IVariableReference;
6447 IFixedExpression fe = InstanceExpression as IFixedExpression;
6448 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6449 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6452 if (InstanceExpression.eclass != ExprClass.Variable) {
6453 ec.Report.SymbolRelatedToPreviousError (spec);
6454 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6455 TypeManager.GetFullNameSignature (spec));
6456 } else if (var != null && var.IsHoisted) {
6457 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6460 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6464 // Set flow-analysis variable info for struct member access. It will be check later
6465 // for precise error reporting
6467 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6468 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6471 if (conditional_access_receiver)
6472 type = LiftMemberType (ec, type);
6474 if (ConditionalAccess && InstanceExpression != null && InstanceExpression.IsNull)
6475 return Constant.CreateConstantFromValue (type, null, loc);
6477 eclass = ExprClass.Variable;
6481 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
6483 spec.CheckObsoleteness (rc, expr.Location);
6486 public void SetFieldAssigned (FlowAnalysisContext fc)
6491 bool lvalue_instance = spec.DeclaringType.IsStruct;
6492 if (lvalue_instance) {
6493 var var = InstanceExpression as IVariableReference;
6494 if (var != null && var.VariableInfo != null) {
6495 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6499 var fe = InstanceExpression as FieldExpr;
6501 Expression instance;
6504 instance = fe.InstanceExpression;
6505 var fe_instance = instance as FieldExpr;
6506 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6507 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6508 var var = InstanceExpression as IVariableReference;
6509 if (var != null && var.VariableInfo == null) {
6510 var var_inst = instance as IVariableReference;
6511 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6512 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6516 if (fe_instance != null) {
6525 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6526 instance.FlowAnalysis (fc);
6528 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6529 InstanceExpression.FlowAnalysis (fc);
6533 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6535 // The return value is always null. Returning a value simplifies calling code.
6537 if (right_side == EmptyExpression.OutAccess) {
6539 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6540 GetSignatureForError ());
6542 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6543 GetSignatureForError ());
6546 return ErrorExpression.Instance;
6549 if (right_side == EmptyExpression.LValueMemberAccess) {
6550 // Already reported as CS1648/CS1650
6551 return ErrorExpression.Instance;
6554 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6556 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6557 GetSignatureForError ());
6559 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6560 GetSignatureForError ());
6562 return ErrorExpression.Instance;
6566 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6567 GetSignatureForError ());
6569 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6570 GetSignatureForError ());
6573 return ErrorExpression.Instance;
6576 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6578 if (HasConditionalAccess ())
6579 Error_NullPropagatingLValue (ec);
6581 if (spec is FixedFieldSpec) {
6582 // It could be much better error message but we want to be error compatible
6583 Error_ValueAssignment (ec, right_side);
6586 Expression e = DoResolve (ec, right_side);
6591 spec.MemberDefinition.SetIsAssigned ();
6593 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6594 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6595 ec.Report.Warning (420, 1, loc,
6596 "`{0}': A volatile field references will not be treated as volatile",
6597 spec.GetSignatureForError ());
6600 if (spec.IsReadOnly) {
6601 // InitOnly fields can only be assigned in constructors or initializers
6602 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6603 return Error_AssignToReadonly (ec, right_side);
6605 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6607 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6608 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6609 return Error_AssignToReadonly (ec, right_side);
6610 // static InitOnly fields cannot be assigned-to in an instance constructor
6611 if (IsStatic && !ec.IsStatic)
6612 return Error_AssignToReadonly (ec, right_side);
6613 // instance constructors can't modify InitOnly fields of other instances of the same type
6614 if (!IsStatic && !(InstanceExpression is This))
6615 return Error_AssignToReadonly (ec, right_side);
6619 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6620 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6621 ec.Report.Warning (197, 1, loc,
6622 "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",
6623 GetSignatureForError ());
6626 eclass = ExprClass.Variable;
6630 public override void FlowAnalysis (FlowAnalysisContext fc)
6632 var var = InstanceExpression as IVariableReference;
6634 var vi = var.VariableInfo;
6635 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6636 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6640 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6641 var le = SkipLeftValueTypeAccess (InstanceExpression);
6643 le.FlowAnalysis (fc);
6649 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
6651 base.FlowAnalysis (fc);
6653 if (conditional_access_receiver)
6654 fc.DefiniteAssignment = da;
6657 static Expression SkipLeftValueTypeAccess (Expression expr)
6659 if (!TypeSpec.IsValueType (expr.Type))
6662 if (expr is VariableReference)
6665 var fe = expr as FieldExpr;
6669 if (fe.InstanceExpression == null)
6672 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6675 public override int GetHashCode ()
6677 return spec.GetHashCode ();
6680 public bool IsFixed {
6683 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6685 IVariableReference variable = InstanceExpression as IVariableReference;
6686 if (variable != null)
6687 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6689 IFixedExpression fe = InstanceExpression as IFixedExpression;
6690 return fe != null && fe.IsFixed;
6694 public override bool Equals (object obj)
6696 FieldExpr fe = obj as FieldExpr;
6700 if (spec != fe.spec)
6703 if (InstanceExpression == null || fe.InstanceExpression == null)
6706 return InstanceExpression.Equals (fe.InstanceExpression);
6709 public void Emit (EmitContext ec, bool leave_copy)
6711 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6715 ec.Emit (OpCodes.Volatile);
6717 ec.Emit (OpCodes.Ldsfld, spec);
6719 var ca = ec.ConditionalAccess;
6722 if (conditional_access_receiver)
6723 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6725 EmitInstance (ec, false);
6728 // Optimization for build-in types
6729 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6730 ec.EmitLoadFromPtr (type);
6732 var ff = spec as FixedFieldSpec;
6734 ec.Emit (OpCodes.Ldflda, spec);
6735 ec.Emit (OpCodes.Ldflda, ff.Element);
6738 ec.Emit (OpCodes.Volatile);
6740 ec.Emit (OpCodes.Ldfld, spec);
6744 if (conditional_access_receiver) {
6745 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6746 ec.ConditionalAccess = ca;
6751 ec.Emit (OpCodes.Dup);
6753 temp = new LocalTemporary (this.Type);
6759 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6761 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6762 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6767 if (ConditionalAccess)
6768 throw new NotImplementedException ("null operator assignment");
6770 if (has_await_source)
6771 source = source.EmitToField (ec);
6773 EmitInstance (ec, prepared);
6778 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6779 ec.Emit (OpCodes.Dup);
6781 temp = new LocalTemporary (this.Type);
6786 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6787 ec.Emit (OpCodes.Volatile);
6789 spec.MemberDefinition.SetIsAssigned ();
6792 ec.Emit (OpCodes.Stsfld, spec);
6794 ec.Emit (OpCodes.Stfld, spec);
6796 if (ec.NotifyEvaluatorOnStore) {
6798 throw new NotImplementedException ("instance field write");
6801 ec.Emit (OpCodes.Dup);
6803 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6814 // Emits store to field with prepared values on stack
6816 public void EmitAssignFromStack (EmitContext ec)
6819 ec.Emit (OpCodes.Stsfld, spec);
6821 ec.Emit (OpCodes.Stfld, spec);
6825 public override void Emit (EmitContext ec)
6830 public override void EmitSideEffect (EmitContext ec)
6832 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6834 if (is_volatile) // || is_marshal_by_ref ())
6835 base.EmitSideEffect (ec);
6838 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6840 if ((mode & AddressOp.Store) != 0)
6841 spec.MemberDefinition.SetIsAssigned ();
6842 if ((mode & AddressOp.Load) != 0)
6843 spec.MemberDefinition.SetIsUsed ();
6846 // Handle initonly fields specially: make a copy and then
6847 // get the address of the copy.
6850 if (spec.IsReadOnly){
6852 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6864 var temp = ec.GetTemporaryLocal (type);
6865 ec.Emit (OpCodes.Stloc, temp);
6866 ec.Emit (OpCodes.Ldloca, temp);
6872 ec.Emit (OpCodes.Ldsflda, spec);
6875 EmitInstance (ec, false);
6876 ec.Emit (OpCodes.Ldflda, spec);
6880 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6882 return MakeExpression (ctx);
6885 public override SLE.Expression MakeExpression (BuilderContext ctx)
6888 return base.MakeExpression (ctx);
6890 return SLE.Expression.Field (
6891 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6892 spec.GetMetaInfo ());
6896 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6898 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6904 // Expression that evaluates to a Property.
6906 // This is not an LValue because we need to re-write the expression. We
6907 // can not take data from the stack and store it.
6909 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6911 Arguments arguments;
6912 FieldExpr backing_field;
6914 public PropertyExpr (PropertySpec spec, Location l)
6917 best_candidate = spec;
6918 type = spec.MemberType;
6923 protected override Arguments Arguments {
6932 protected override TypeSpec DeclaringType {
6934 return best_candidate.DeclaringType;
6938 public override string Name {
6940 return best_candidate.Name;
6944 public bool IsAutoPropertyAccess {
6946 var prop = best_candidate.MemberDefinition as Property;
6947 return prop != null && prop.BackingField != null;
6951 public override bool IsInstance {
6957 public override bool IsStatic {
6959 return best_candidate.IsStatic;
6963 public override string KindName {
6964 get { return "property"; }
6967 public PropertySpec PropertyInfo {
6969 return best_candidate;
6975 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6977 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6980 var args_count = arguments == null ? 0 : arguments.Count;
6981 if (args_count != body.Parameters.Count && args_count == 0)
6984 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6985 mg.InstanceExpression = InstanceExpression;
6990 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6992 return new PropertyExpr (spec, loc) {
6998 public override Expression CreateExpressionTree (ResolveContext ec)
7000 if (ConditionalAccess) {
7001 Error_NullShortCircuitInsideExpressionTree (ec);
7005 if (IsSingleDimensionalArrayLength ()) {
7006 args = new Arguments (1);
7007 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
7008 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
7011 args = new Arguments (2);
7012 if (InstanceExpression == null)
7013 args.Add (new Argument (new NullLiteral (loc)));
7015 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
7016 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
7017 return CreateExpressionFactoryCall (ec, "Property", args);
7020 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
7022 DoResolveLValue (rc, null);
7023 return new TypeOfMethod (Setter, loc);
7026 public override string GetSignatureForError ()
7028 return best_candidate.GetSignatureForError ();
7031 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
7034 return base.MakeExpression (ctx);
7036 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
7040 public override SLE.Expression MakeExpression (BuilderContext ctx)
7043 return base.MakeExpression (ctx);
7045 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
7049 void Error_PropertyNotValid (ResolveContext ec)
7051 ec.Report.SymbolRelatedToPreviousError (best_candidate);
7052 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
7053 GetSignatureForError ());
7056 bool IsSingleDimensionalArrayLength ()
7058 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
7061 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
7062 return ac != null && ac.Rank == 1;
7065 public override void Emit (EmitContext ec, bool leave_copy)
7068 // Special case: length of single dimension array property is turned into ldlen
7070 if (IsSingleDimensionalArrayLength ()) {
7071 if (conditional_access_receiver) {
7072 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7075 EmitInstance (ec, false);
7077 ec.Emit (OpCodes.Ldlen);
7078 ec.Emit (OpCodes.Conv_I4);
7080 if (conditional_access_receiver) {
7081 ec.CloseConditionalAccess (type);
7087 base.Emit (ec, leave_copy);
7090 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7092 if (backing_field != null) {
7093 backing_field.EmitAssign (ec, source, leave_copy, false);
7098 LocalTemporary await_source_arg = null;
7100 if (isCompound && !(source is DynamicExpressionStatement)) {
7101 emitting_compound_assignment = true;
7104 if (has_await_arguments) {
7105 await_source_arg = new LocalTemporary (Type);
7106 await_source_arg.Store (ec);
7108 args = new Arguments (1);
7109 args.Add (new Argument (await_source_arg));
7112 temp = await_source_arg;
7115 has_await_arguments = false;
7120 ec.Emit (OpCodes.Dup);
7121 temp = new LocalTemporary (this.Type);
7126 args = arguments ?? new Arguments (1);
7130 temp = new LocalTemporary (this.Type);
7132 args.Add (new Argument (temp));
7134 args.Add (new Argument (source));
7138 emitting_compound_assignment = false;
7140 var call = new CallEmitter ();
7141 call.InstanceExpression = InstanceExpression;
7143 call.InstanceExpressionOnStack = true;
7145 if (ConditionalAccess) {
7146 call.ConditionalAccess = true;
7150 call.Emit (ec, Setter, args, loc);
7152 call.EmitStatement (ec, Setter, args, loc);
7159 if (await_source_arg != null) {
7160 await_source_arg.Release (ec);
7164 public override void FlowAnalysis (FlowAnalysisContext fc)
7166 var prop = best_candidate.MemberDefinition as Property;
7167 if (prop != null && prop.BackingField != null) {
7168 var var = InstanceExpression as IVariableReference;
7170 var vi = var.VariableInfo;
7171 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
7172 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
7176 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
7181 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7183 base.FlowAnalysis (fc);
7185 if (conditional_access_receiver)
7186 fc.DefiniteAssignment = da;
7189 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
7191 eclass = ExprClass.PropertyAccess;
7193 if (best_candidate.IsNotCSharpCompatible) {
7194 Error_PropertyNotValid (rc);
7197 ResolveInstanceExpression (rc, right_side);
7199 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7200 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7201 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7203 type = p.MemberType;
7207 DoBestMemberChecks (rc, best_candidate);
7209 // Handling of com-imported properties with any number of default property parameters
7210 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7211 var p = best_candidate.Get.Parameters;
7212 arguments = new Arguments (p.Count);
7213 for (int i = 0; i < p.Count; ++i) {
7214 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7216 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7217 var p = best_candidate.Set.Parameters;
7218 arguments = new Arguments (p.Count - 1);
7219 for (int i = 0; i < p.Count - 1; ++i) {
7220 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7227 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7229 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7232 var prop = best_candidate.MemberDefinition as Property;
7233 if (prop == null || prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
7234 var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (best_candidate.Name, best_candidate.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
7238 prop = (Property)ps.MemberDefinition;
7241 var spec = prop.BackingField;
7245 if (rc.IsStatic != spec.IsStatic)
7248 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7251 backing_field = new FieldExpr (prop.BackingField, loc);
7252 backing_field.ResolveLValue (rc, rhs);
7256 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
7258 if (!best_candidate.IsAccessible (rc))
7259 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), expr.Location);
7261 best_candidate.CheckObsoleteness (rc, expr.Location);
7264 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7266 if (backing_field != null) {
7267 backing_field.SetFieldAssigned (fc);
7271 if (!IsAutoPropertyAccess)
7274 var prop = best_candidate.MemberDefinition as Property;
7275 if (prop != null && prop.BackingField != null) {
7276 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7277 if (lvalue_instance) {
7278 var var = InstanceExpression as IVariableReference;
7279 if (var != null && var.VariableInfo != null) {
7280 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7286 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7288 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7292 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7294 // getter and setter can be different for base calls
7295 MethodSpec getter, setter;
7296 protected T best_candidate;
7298 protected LocalTemporary temp;
7299 protected bool emitting_compound_assignment;
7300 protected bool has_await_arguments;
7302 protected PropertyOrIndexerExpr (Location l)
7309 protected abstract Arguments Arguments { get; set; }
7311 public MethodSpec Getter {
7320 public MethodSpec Setter {
7331 protected override Expression DoResolve (ResolveContext ec)
7333 if (eclass == ExprClass.Unresolved) {
7334 ResolveConditionalAccessReceiver (ec);
7336 var expr = OverloadResolve (ec, null);
7341 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, conditional_access_receiver))
7342 return expr.Resolve (ec);
7345 if (conditional_access_receiver) {
7346 type = LiftMemberType (ec, type);
7350 if (!ResolveGetter (ec))
7356 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7358 if (HasConditionalAccess ())
7359 Error_NullPropagatingLValue (rc);
7361 if (right_side == EmptyExpression.OutAccess) {
7362 if (best_candidate?.MemberType.Kind == MemberKind.ByRef) {
7363 if (Arguments?.ContainsEmitWithAwait () == true) {
7364 rc.Report.Error (8178, loc, "`await' cannot be used in an expression containing a call to `{0}' because it returns by reference",
7365 GetSignatureForError ());
7371 // TODO: best_candidate can be null at this point
7372 INamedBlockVariable variable = null;
7373 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7374 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7375 best_candidate.Name);
7377 right_side.DoResolveLValue (rc, this);
7382 if (eclass == ExprClass.Unresolved) {
7383 var expr = OverloadResolve (rc, right_side);
7388 return expr.ResolveLValue (rc, right_side);
7390 ResolveInstanceExpression (rc, right_side);
7393 if (!best_candidate.HasSet) {
7394 if (ResolveAutopropertyAssignment (rc, right_side))
7397 if (best_candidate.MemberType.Kind == MemberKind.ByRef) {
7398 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7399 return ByRefDereference.Create(this).Resolve(rc);
7402 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7403 GetSignatureForError ());
7407 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7408 if (best_candidate.HasDifferentAccessibility) {
7409 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7410 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7411 GetSignatureForError ());
7413 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7414 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7418 if (best_candidate.HasDifferentAccessibility)
7419 CheckProtectedMemberAccess (rc, best_candidate.Set);
7421 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7425 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7427 var ca = ec.ConditionalAccess;
7428 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7430 call.Emit (ec, method, arguments, loc);
7432 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7433 ec.ConditionalAccess = ca;
7437 // Implements the IAssignMethod interface for assignments
7439 public virtual void Emit (EmitContext ec, bool leave_copy)
7441 var call = new CallEmitter ();
7442 call.ConditionalAccess = ConditionalAccess;
7443 call.InstanceExpression = InstanceExpression;
7444 if (has_await_arguments)
7445 call.HasAwaitArguments = true;
7447 call.DuplicateArguments = emitting_compound_assignment;
7449 if (conditional_access_receiver)
7450 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7452 call.Emit (ec, Getter, Arguments, loc);
7454 if (call.HasAwaitArguments) {
7455 InstanceExpression = call.InstanceExpression;
7456 Arguments = call.EmittedArguments;
7457 has_await_arguments = true;
7461 ec.Emit (OpCodes.Dup);
7462 temp = new LocalTemporary (Type);
7467 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7469 public override void Emit (EmitContext ec)
7474 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7476 has_await_arguments = true;
7481 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7483 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7485 bool ResolveGetter (ResolveContext rc)
7487 if (!best_candidate.HasGet) {
7488 if (InstanceExpression != EmptyExpression.Null) {
7489 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7490 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7491 best_candidate.GetSignatureForError ());
7494 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7495 if (best_candidate.HasDifferentAccessibility) {
7496 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7497 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7498 TypeManager.CSharpSignature (best_candidate));
7500 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7501 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7505 if (best_candidate.HasDifferentAccessibility) {
7506 CheckProtectedMemberAccess (rc, best_candidate.Get);
7509 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7513 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7520 /// Fully resolved expression that evaluates to an Event
7522 public class EventExpr : MemberExpr, IAssignMethod
7524 readonly EventSpec spec;
7527 public EventExpr (EventSpec spec, Location loc)
7535 protected override TypeSpec DeclaringType {
7537 return spec.DeclaringType;
7541 public override string Name {
7547 public override bool IsInstance {
7549 return !spec.IsStatic;
7553 public override bool IsStatic {
7555 return spec.IsStatic;
7559 public override string KindName {
7560 get { return "event"; }
7563 public MethodSpec Operator {
7571 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7574 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7576 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7577 if (spec.BackingField != null &&
7578 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7580 spec.MemberDefinition.SetIsUsed ();
7582 spec.CheckObsoleteness (ec, loc);
7584 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7585 Error_AssignmentEventOnly (ec);
7587 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7589 InstanceExpression = null;
7591 return ml.ResolveMemberAccess (ec, left, original);
7595 return base.ResolveMemberAccess (ec, left, original);
7598 public override Expression CreateExpressionTree (ResolveContext ec)
7600 throw new NotSupportedException ("ET");
7603 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7605 if (right_side == EmptyExpression.EventAddition) {
7606 op = spec.AccessorAdd;
7607 } else if (right_side == EmptyExpression.EventSubtraction) {
7608 op = spec.AccessorRemove;
7612 Error_AssignmentEventOnly (ec);
7616 if (HasConditionalAccess ())
7617 Error_NullPropagatingLValue (ec);
7619 op = CandidateToBaseOverride (ec, op);
7623 protected override Expression DoResolve (ResolveContext ec)
7625 eclass = ExprClass.EventAccess;
7626 type = spec.MemberType;
7628 ResolveInstanceExpression (ec, null);
7630 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7631 Error_AssignmentEventOnly (ec);
7634 DoBestMemberChecks (ec, spec);
7638 public override void Emit (EmitContext ec)
7640 throw new NotSupportedException ();
7641 //Error_CannotAssign ();
7644 #region IAssignMethod Members
7646 public void Emit (EmitContext ec, bool leave_copy)
7648 throw new NotImplementedException ();
7651 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7653 if (leave_copy || !isCompound)
7654 throw new NotImplementedException ("EventExpr::EmitAssign");
7656 Arguments args = new Arguments (1);
7657 args.Add (new Argument (source));
7659 // TODO: Wrong, needs receiver
7660 // if (NullShortCircuit) {
7661 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7664 var call = new CallEmitter ();
7665 call.InstanceExpression = InstanceExpression;
7666 call.ConditionalAccess = ConditionalAccess;
7667 call.EmitStatement (ec, op, args, loc);
7669 // if (NullShortCircuit)
7670 // ec.CloseConditionalAccess (null);
7675 void Error_AssignmentEventOnly (ResolveContext ec)
7677 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7678 ec.Report.Error (79, loc,
7679 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7680 GetSignatureForError ());
7682 ec.Report.Error (70, loc,
7683 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7684 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7688 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7690 name = name.Substring (0, name.LastIndexOf ('.'));
7691 base.Error_CannotCallAbstractBase (rc, name);
7694 public override string GetSignatureForError ()
7696 return TypeManager.CSharpSignature (spec);
7699 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
7701 spec.CheckObsoleteness (rc, expr.Location);
7704 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7706 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7710 public class TemporaryVariableReference : VariableReference
7712 public class Declarator : Statement
7714 TemporaryVariableReference variable;
7716 public Declarator (TemporaryVariableReference variable)
7718 this.variable = variable;
7722 protected override void DoEmit (EmitContext ec)
7724 variable.li.CreateBuilder (ec);
7727 public override void Emit (EmitContext ec)
7729 // Don't create sequence point
7733 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7738 protected override void CloneTo (CloneContext clonectx, Statement target)
7746 public TemporaryVariableReference (LocalVariable li, Location loc)
7749 this.type = li.Type;
7753 public override bool IsLockedByStatement {
7761 public LocalVariable LocalInfo {
7767 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
7769 var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
7770 return new TemporaryVariableReference (li, loc);
7773 protected override Expression DoResolve (ResolveContext ec)
7775 eclass = ExprClass.Variable;
7778 // Don't capture temporary variables except when using
7779 // state machine redirection and block yields
7781 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7782 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7783 ec.IsVariableCapturingRequired) {
7784 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7785 storey.CaptureLocalVariable (ec, li);
7791 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7793 return Resolve (ec);
7796 public override void Emit (EmitContext ec)
7798 li.CreateBuilder (ec);
7803 public void EmitAssign (EmitContext ec, Expression source)
7805 li.CreateBuilder (ec);
7807 EmitAssign (ec, source, false, false);
7810 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7812 return li.HoistedVariant;
7815 public override bool IsFixed {
7816 get { return true; }
7819 public override bool IsRef {
7820 get { return false; }
7823 public override string Name {
7824 get { throw new NotImplementedException (); }
7827 public override void SetHasAddressTaken ()
7829 throw new NotImplementedException ();
7832 protected override ILocalVariable Variable {
7836 public override VariableInfo VariableInfo {
7837 get { return null; }
7842 /// Handles `var' contextual keyword; var becomes a keyword only
7843 /// if no type called var exists in a variable scope
7845 class VarExpr : SimpleName
7847 public VarExpr (Location loc)
7852 public bool InferType (ResolveContext ec, Expression rhs)
7855 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7859 if (type.Kind == MemberKind.Void || InternalType.HasNoType (type) || (rhs is TupleLiteral && TupleLiteral.ContainsNoTypeElement (type))) {
7860 ec.Report.Error (815, loc,
7861 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7862 type.GetSignatureForError ());
7863 type = InternalType.ErrorType;
7867 eclass = ExprClass.Variable;
7871 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7873 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7874 base.Error_TypeOrNamespaceNotFound (ec);
7876 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");