Resolve switch cases without look aheah look-up. Fixes #12583
[mono.git] / mcs / mcs / ecore.cs
index cec0a6f2243a5e423baf708bffd9777338d75910..dd3681529e0eb04c33be636a1d283bfb610cab05 100644 (file)
@@ -152,6 +152,35 @@ namespace Mono.CSharp {
                        }
                }
 
+               //
+               // Used to workaround parser limitation where we cannot get
+               // start of statement expression location
+               //
+               public virtual Location StartLocation {
+                       get {
+                               return loc;
+                       }
+               }
+
+               public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
+               {
+                       //
+                       // Return method-group expression when the expression can be used as
+                       // lambda replacement. A good example is array sorting where instead of
+                       // code like
+                       //
+                       //  Array.Sort (s, (a, b) => String.Compare (a, b));
+                       //
+                       // we can use method group directly
+                       //
+                       //  Array.Sort (s, String.Compare);
+                       //
+                       // Correct overload will be used because we do the reduction after
+                       // best candidate was found.
+                       //
+                       return null;
+               }
+
                //
                // Returns true when the expression during Emit phase breaks stack
                // by using await expression
@@ -222,7 +251,7 @@ namespace Mono.CSharp {
                public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
                {
                        rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
-                               name, TypeManager.CSharpName (type));
+                               name, type.GetSignatureForError ());
                }
 
                protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
@@ -253,7 +282,10 @@ namespace Mono.CSharp {
                protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
                {
                        // The error was already reported as CS1660
-                       if (type == InternalType.AnonymousMethod || type == InternalType.ErrorType)
+                       if (type == InternalType.AnonymousMethod)
+                               return;
+
+                       if (type == InternalType.ErrorType || target == InternalType.ErrorType)
                                return;
 
                        string from_type = type.GetSignatureForError ();
@@ -322,13 +354,15 @@ namespace Mono.CSharp {
                {
                        ec.Report.SymbolRelatedToPreviousError (type);
                        ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
-                               TypeManager.CSharpName (type), name);
+                               type.GetSignatureForError (), name);
                }
 
                public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
                {
                        if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
                                // Already reported as CS1612
+                       } else if (rhs == EmptyExpression.OutAccess) {
+                               rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
                        } else {
                                rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
                        }
@@ -463,10 +497,7 @@ namespace Mono.CSharp {
 
                        if (e == null) {
                                if (errors == ec.Report.Errors) {
-                                       if (out_access)
-                                               ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
-                                       else
-                                               Error_ValueAssignment (ec, right_side);
+                                       Error_ValueAssignment (ec, right_side);
                                }
                                return null;
                        }
@@ -480,6 +511,23 @@ namespace Mono.CSharp {
                        return e;
                }
 
+               public Constant ResolveLabelConstant (ResolveContext rc)
+               {
+                       var expr = Resolve (rc);
+                       if (expr == null)
+                               return null;
+
+                       Constant c = expr as Constant;
+                       if (c == null) {
+                               if (c.type != InternalType.ErrorType)
+                                       rc.Report.Error (150, StartLocation, "A constant value is expected");
+
+                               return null;
+                       }
+
+                       return c;
+               }
+
                public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
                {
                        rc.Module.Compiler.Report.Error (182, loc,
@@ -1055,8 +1103,8 @@ namespace Mono.CSharp {
        ///   being that they would support an extra Emition interface that
        ///   does not leave a result on the stack.
        /// </summary>
-       public abstract class ExpressionStatement : Expression {
-
+       public abstract class ExpressionStatement : Expression
+       {
                public ExpressionStatement ResolveStatement (BlockContext ec)
                {
                        Expression e = Resolve (ec);
@@ -1446,7 +1494,7 @@ namespace Mono.CSharp {
 
                public override string GetSignatureForError()
                {
-                       return TypeManager.CSharpName (Type);
+                       return Type.GetSignatureForError ();
                }
 
                public override object GetValue ()
@@ -1505,7 +1553,7 @@ namespace Mono.CSharp {
                        }
                }
 
-               public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
+               public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
                {
                        if (Child.Type == target_type)
                                return Child;
@@ -2389,15 +2437,15 @@ namespace Mono.CSharp {
                        }
                }
 
-               public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
+               public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
                {
-                       FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
+                       FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
 
                        if (fne != null) {
                                if (fne.Type != null && Arity > 0) {
                                        if (HasTypeArguments) {
                                                GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
-                                               if (ct.ResolveAsType (ec) == null)
+                                               if (ct.ResolveAsType (mc) == null)
                                                        return null;
 
                                                return ct;
@@ -2413,21 +2461,21 @@ namespace Mono.CSharp {
                                        return fne;
                        }
 
-                       if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
-                               if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
-                                       ec.Module.Compiler.Report.Error (1980, Location,
+                       if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
+                               if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
+                                       mc.Module.Compiler.Report.Error (1980, Location,
                                                "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
-                                               ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
+                                               mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
                                }
 
                                fne = new DynamicTypeExpr (loc);
-                               fne.ResolveAsType (ec);
+                               fne.ResolveAsType (mc);
                        }
 
                        if (fne != null)
                                return fne;
 
-                       Error_TypeOrNamespaceNotFound (ec);
+                       Error_TypeOrNamespaceNotFound (mc);
                        return null;
                }
 
@@ -3215,7 +3263,7 @@ namespace Mono.CSharp {
        class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
        {
                ExtensionMethodCandidates candidates;
-               public readonly Expression ExtensionExpression;
+               public Expression ExtensionExpression;
 
                public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
                        : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
@@ -3259,8 +3307,16 @@ namespace Mono.CSharp {
                        if (arguments == null)
                                arguments = new Arguments (1);
 
+                       ExtensionExpression = ExtensionExpression.Resolve (ec);
+                       if (ExtensionExpression == null)
+                               return null;
+
+                       var cand = candidates;
                        arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
                        var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
+                       
+                       // Restore candidates in case we are running in probing mode 
+                       candidates = cand;
 
                        // Store resolved argument and restore original arguments
                        if (res == null) {
@@ -3470,7 +3526,7 @@ namespace Mono.CSharp {
                public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
                {
                        ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
-                               Name, TypeManager.CSharpName (target));
+                               Name, target.GetSignatureForError ());
                }
 
                public static bool IsExtensionMethodArgument (Expression expr)
@@ -4522,17 +4578,18 @@ namespace Mono.CSharp {
                                // It can be applicable in expanded form (when not doing exact match like for delegates)
                                //
                                if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
-                                       if (!params_expanded_form)
+                                       if (!params_expanded_form) {
                                                pt = ((ElementTypeSpec) pt).Element;
+                                       }
 
                                        if (score > 0)
                                                score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
 
-                                       if (score == 0) {
-                                               params_expanded_form = true;
-                                       } else if (score < 0) {
+                                       if (score < 0) {
                                                params_expanded_form = true;
                                                dynamicArgument = true;
+                                       } else if (score == 0 || arg_count > pd.Count) {
+                                               params_expanded_form = true;
                                        }
                                }
 
@@ -5011,14 +5068,14 @@ namespace Mono.CSharp {
                        string index = (idx + 1).ToString ();
                        if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
                                if ((mod & Parameter.Modifier.RefOutMask) == 0)
-                                       ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
+                                       ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
                                                index, Parameter.GetModifierSignature (a.Modifier));
                                else
-                                       ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
+                                       ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
                                                index, Parameter.GetModifierSignature (mod));
                        } else {
                                string p1 = a.GetSignatureForError ();
-                               string p2 = TypeManager.CSharpName (paramType);
+                               string p2 = paramType.GetSignatureForError ();
 
                                if (p1 == p2) {
                                        p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
@@ -5611,6 +5668,11 @@ namespace Mono.CSharp {
                
                override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
                {
+                       if (spec is FixedFieldSpec) {
+                               // It could be much better error message but we want to be error compatible
+                               Error_ValueAssignment (ec, right_side);
+                       }
+
                        Expression e = DoResolve (ec, right_side);
 
                        if (e == null)
@@ -5929,6 +5991,21 @@ namespace Mono.CSharp {
 
                #endregion
 
+               public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
+               {
+                       if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
+                               return null;
+
+                       var args_count = arguments == null ? 0 : arguments.Count;
+                       if (args_count != body.Parameters.Count && args_count == 0)
+                               return null;
+
+                       var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
+                       mg.InstanceExpression = InstanceExpression;
+
+                       return mg;
+               }
+
                public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
                {
                        return new PropertyExpr (spec, loc) {
@@ -6550,8 +6627,9 @@ namespace Mono.CSharp {
                        // Don't capture temporary variables except when using
                        // state machine redirection and block yields
                        //
-                       if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator &&
-                               ec.CurrentBlock.Explicit.HasYield && ec.IsVariableCapturingRequired) {
+                       if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer &&
+                               (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
+                               ec.IsVariableCapturingRequired) {
                                AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
                                storey.CaptureLocalVariable (ec, li);
                        }