Merge pull request #1185 from esdrubal/http-reuse
[mono.git] / mcs / mcs / ecore.cs
index 788b9e1dee5a0746f107597d6cca6192cb560e1f..3143908b63accad973ddba473d1f532987e364e5 100644 (file)
@@ -228,12 +228,12 @@ namespace Mono.CSharp {
                // This is used if the expression should be resolved as a type or namespace name.
                // the default implementation fails.   
                //
-               public virtual TypeSpec ResolveAsType (IMemberContext mc)
+               public virtual TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
                {
-                       ResolveContext ec = new ResolveContext (mc);
-                       Expression e = Resolve (ec);
+                       var rc = mc as ResolveContext ?? new ResolveContext (mc);
+                       Expression e = Resolve (rc);
                        if (e != null)
-                               e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
+                               e.Error_UnexpectedKind (rc, ResolveFlags.Type, loc);
 
                        return null;
                }
@@ -429,6 +429,52 @@ namespace Mono.CSharp {
                {
                        return type.GetDefinition ().GetSignatureForError ();
                }
+
+               public static bool IsNeverNull (Expression expr)
+               {
+                       if (expr is This || expr is New || expr is ArrayCreation || expr is DelegateCreation || expr is ConditionalMemberAccess)
+                               return true;
+
+                       var c = expr as Constant;
+                       if (c != null)
+                               return !c.IsNull;
+
+                       var tc = expr as TypeCast;
+                       if (tc != null)
+                               return IsNeverNull (tc.Child);
+
+                       return false;
+               }
+
+               protected static bool IsNullPropagatingValid (TypeSpec type)
+               {
+                       switch (type.Kind) {
+                       case MemberKind.Struct:
+                               return type.IsNullableType;
+                       case MemberKind.Enum:
+                       case MemberKind.Void:
+                       case MemberKind.PointerType:
+                               return false;
+                       case MemberKind.InternalCompilerType:
+                               return type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
+                       case MemberKind.TypeParameter:
+                               return !((TypeParameterSpec) type).IsValueType;
+                       default:
+                               return true;
+                       }
+               }
+
+               public virtual bool HasConditionalAccess ()
+               {
+                       return false;
+               }
+
+               protected static TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
+               {
+                       return TypeSpec.IsValueType (type) && !type.IsNullableType ?
+                               Nullable.NullableInfo.MakeType (rc.Module, type) :
+                               type;
+               }
               
                /// <summary>
                ///   Resolves an expression and performs semantic analysis on it.
@@ -720,12 +766,19 @@ namespace Mono.CSharp {
                        if (ctors == null) {
                                switch (type.Kind) {
                                case MemberKind.Struct:
+                                       // Every struct has implicit default constructor if not provided by user
+                                       if (args == null)
+                                               return null;
+
                                        rc.Report.SymbolRelatedToPreviousError (type);
                                        // Report meaningful error for struct as they always have default ctor in C# context
                                        OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
                                        break;
                                case MemberKind.MissingType:
                                case MemberKind.InternalCompilerType:
+// LAMESPEC: dynamic is not really object
+//                                     if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
+//                                             goto default;
                                        break;
                                default:
                                        rc.Report.SymbolRelatedToPreviousError (type);
@@ -737,6 +790,18 @@ namespace Mono.CSharp {
                                return null;
                        }
 
+                       if (args == null && type.IsStruct) {
+                               bool includes_empty = false;
+                               foreach (MethodSpec ctor in ctors) {
+                                       if (ctor.Parameters.IsEmpty) {
+                                               includes_empty = true;
+                                       }
+                               }
+
+                               if (!includes_empty)
+                                       return null;
+                       }
+
                        var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
                        if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
                                r.InstanceQualifier = new ConstructorInstanceQualifier (type);
@@ -751,7 +816,10 @@ namespace Mono.CSharp {
                        None = 0,
                        InvocableOnly = 1,
                        ExactArity = 1 << 2,
-                       ReadAccess = 1 << 3
+                       ReadAccess = 1 << 3,
+                       EmptyArguments = 1 << 4,
+                       IgnoreArity = 1 << 5,
+                       IgnoreAmbiguity = 1 << 6
                }
 
                //
@@ -845,7 +913,7 @@ namespace Mono.CSharp {
                                }
 
                                if (non_method != null) {
-                                       if (ambig_non_method != null && rc != null) {
+                                       if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
                                                var report = rc.Module.Compiler.Report;
                                                report.SymbolRelatedToPreviousError (non_method);
                                                report.SymbolRelatedToPreviousError (ambig_non_method);
@@ -936,10 +1004,25 @@ namespace Mono.CSharp {
                        ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
                }
 
+               protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
+               {
+                       rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
+               }
+
                public virtual void FlowAnalysis (FlowAnalysisContext fc)
                {
                }
 
+               //
+               // Special version of flow analysis for expressions which can return different
+               // on-true and on-false result. Used by &&, ||, ?: expressions
+               //
+               public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
+               {
+                       FlowAnalysis (fc);
+                       fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
+               }
+
                /// <summary>
                ///   Returns an expression that can be used to invoke operator true
                ///   on the expression if it exists.
@@ -961,7 +1044,11 @@ namespace Mono.CSharp {
                static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
                {
                        var op = is_true ? Operator.OpType.True : Operator.OpType.False;
-                       var methods = MemberCache.GetUserOperator (e.type, op, false);
+                       var type = e.type;
+                       if (type.IsNullableType)
+                               type = Nullable.NullableInfo.GetUnderlyingType (type);
+
+                       var methods = MemberCache.GetUserOperator (type, op, false);
                        if (methods == null)
                                return null;
 
@@ -2476,6 +2563,11 @@ namespace Mono.CSharp {
                                (targs == null || targs.Equals (atne.targs));
                }
 
+               protected void Error_OpenGenericTypeIsNotAllowed (IMemberContext mc)
+               {
+                       mc.Module.Compiler.Report.Error (7003, Location, "Unbound generic name is not valid in this context");
+               }
+
                public override int GetHashCode ()
                {
                        return Name.GetHashCode ();
@@ -2548,6 +2640,11 @@ namespace Mono.CSharp {
                        return SimpleNameResolve (ec, right_side);
                }
 
+               public void Error_NameDoesNotExist (ResolveContext rc)
+               {
+                       rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
+               }
+
                protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
                {
                        if (ctx.CurrentType != null) {
@@ -2592,7 +2689,7 @@ namespace Mono.CSharp {
                        }
                }
 
-               public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
+               public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
                {
                        FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
 
@@ -2606,6 +2703,9 @@ namespace Mono.CSharp {
                                                return ct;
                                        }
 
+                                       if (!allowUnboundTypeArguments)
+                                               Error_OpenGenericTypeIsNotAllowed (mc);
+
                                        return new GenericOpenTypeExpr (fne.Type, loc);
                                }
 
@@ -2756,10 +2856,22 @@ namespace Mono.CSharp {
                                                        rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
                                                }
 
-                                               return ResolveAsTypeOrNamespace (rc);
+                                               return ResolveAsTypeOrNamespace (rc, false);
+                                       }
+                               }
+
+                               var mg = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
+                               if (mg != null) {
+                                       if (Arity > 0) {
+                                               targs.Resolve (rc);
+                                               mg.SetTypeArguments (rc, targs);
                                        }
+                                       return mg;
                                }
 
+                               if (Name == "nameof")
+                                       return new NameOf (this);
+
                                if (errorMode) {
                                        if (variable_found) {
                                                rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
@@ -2786,17 +2898,6 @@ namespace Mono.CSharp {
 
                                                                ct = ct.DeclaringType;
                                                        } while (ct != null);
-                                               } else {
-                                                       var cos = rc.CurrentMemberDefinition.Parent as ClassOrStruct;
-                                                       if (cos != null && cos.PrimaryConstructorParameters != null) {
-                                                               foreach (var p in cos.PrimaryConstructorParameters.FixedParameters) {
-                                                                       if (p.Name == Name) {
-                                                                               rc.Report.Error (9007, loc, "Primary constructor parameter `{0}' is not available in this context when using ref or out modifier",
-                                                                                       Name);
-                                                                               return null;
-                                                                       }
-                                                               }
-                                                       }
                                                }
 
                                                if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
@@ -2816,7 +2917,7 @@ namespace Mono.CSharp {
 
                                                e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
                                                if (e != null) {
-                                                       if (e.Type.Arity != Arity) {
+                                                       if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
                                                                Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
                                                                return e;
                                                        }
@@ -2830,7 +2931,7 @@ namespace Mono.CSharp {
                                                        }
                                                }
 
-                                               rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
+                                               Error_NameDoesNotExist (rc);
                                        }
 
                                        return ErrorExpression.Instance;
@@ -2896,16 +2997,16 @@ namespace Mono.CSharp {
                        throw new NotSupportedException ("ET");
                }
 
-               public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
+               public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
 
                //
                // This is used to resolve the expression as a type, a null
                // value will be returned if the expression is not a type
                // reference
                //
-               public override TypeSpec ResolveAsType (IMemberContext mc)
+               public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
                {
-                       FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
+                       FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
 
                        if (fne == null)
                                return null;
@@ -2956,7 +3057,7 @@ namespace Mono.CSharp {
        /// </summary>
        public abstract class TypeExpr : FullNamedExpression
        {
-               public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
+               public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
                {
                        ResolveAsType (mc);
                        return this;
@@ -2995,7 +3096,7 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
-               public sealed override TypeSpec ResolveAsType (IMemberContext ec)
+               public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
                {
                        return type;
                }
@@ -3024,7 +3125,7 @@ namespace Mono.CSharp {
                        throw new NotImplementedException ();
                }
 
-               public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
+               public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
                {
                        return this;
                }
@@ -3115,6 +3216,8 @@ namespace Mono.CSharp {
        /// </summary>
        public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
        {
+               protected bool conditional_access_receiver;
+
                //
                // An instance expression associated with this member, if it's a
                // non-static member
@@ -3153,6 +3256,8 @@ namespace Mono.CSharp {
                        get;
                }
 
+               public bool ConditionalAccess { get; set; }
+
                protected abstract TypeSpec DeclaringType {
                        get;
                }
@@ -3291,6 +3396,11 @@ namespace Mono.CSharp {
                        return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
                }
 
+               public override bool HasConditionalAccess ()
+               {
+                       return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
+               }
+
                static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
                {
                        do {
@@ -3346,8 +3456,23 @@ namespace Mono.CSharp {
 
                public override void FlowAnalysis (FlowAnalysisContext fc)
                {
-                       if (InstanceExpression != null)
+                       if (InstanceExpression != null) {
                                InstanceExpression.FlowAnalysis (fc);
+
+                               if (ConditionalAccess) {
+                                       fc.BranchConditionalAccessDefiniteAssignment ();
+                               }
+                       }
+               }
+
+               protected void ResolveConditionalAccessReceiver (ResolveContext rc)
+               {
+                       if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
+                               if (HasConditionalAccess ()) {
+                                       conditional_access_receiver = true;
+                                       rc.Set (ResolveContext.Options.ConditionalAccessReceiver);
+                               }
+                       }
                }
 
                public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
@@ -3358,7 +3483,7 @@ namespace Mono.CSharp {
                        //
                        // Check intermediate value modification which won't have any effect
                        //
-                       if (rhs != null && InstanceExpression.Type.IsStruct) {
+                       if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
                                var fexpr = InstanceExpression as FieldExpr;
                                if (fexpr != null) {
                                        if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
@@ -3496,7 +3621,7 @@ namespace Mono.CSharp {
 
                public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
                {
-                       if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
+                       if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
                                ec.Report.Warning (1720, 1, left.Location,
                                        "Expression will always cause a `{0}'", "System.NullReferenceException");
                        }
@@ -3507,25 +3632,8 @@ namespace Mono.CSharp {
 
                protected void EmitInstance (EmitContext ec, bool prepare_for_load)
                {
-                       TypeSpec instance_type = InstanceExpression.Type;
-                       if (TypeSpec.IsValueType (instance_type)) {
-                               if (InstanceExpression is IMemoryLocation) {
-                                       ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
-                               } else {
-                                       // Cannot release the temporary variable when its address
-                                       // is required to be on stack for any parent
-                                       LocalTemporary t = new LocalTemporary (instance_type);
-                                       InstanceExpression.Emit (ec);
-                                       t.Store (ec);
-                                       t.AddressOf (ec, AddressOp.Store);
-                               }
-                       } else {
-                               InstanceExpression.Emit (ec);
-
-                               // Only to make verifier happy
-                               if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
-                                       ec.Emit (OpCodes.Box, instance_type);
-                       }
+                       var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
+                       inst.Emit (ec, ConditionalAccess);
 
                        if (prepare_for_load)
                                ec.Emit (OpCodes.Dup);
@@ -3593,6 +3701,13 @@ namespace Mono.CSharp {
                        get { return true; }
                }
 
+               public override void FlowAnalysis (FlowAnalysisContext fc)
+               {
+                       if (ConditionalAccess) {
+                               fc.BranchConditionalAccessDefiniteAssignment ();
+                       }
+               }
+
                //
                // For extension methodgroup we are not looking for base members but parent
                // namespace extension methods
@@ -3629,7 +3744,8 @@ namespace Mono.CSharp {
                                return null;
 
                        var cand = candidates;
-                       arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
+                       var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
+                       arguments.Insert (0, new Argument (ExtensionExpression, atype));
                        var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
                        
                        // Restore candidates in case we are running in probing mode 
@@ -3825,7 +3941,10 @@ namespace Mono.CSharp {
                        if (IsConditionallyExcluded)
                                ec.Report.Error (765, loc,
                                        "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
-                       
+
+                       if (ConditionalAccess)
+                               Error_NullShortCircuitInsideExpressionTree (ec);
+
                        return new TypeOfMethod (best_candidate, loc);
                }
                
@@ -3846,12 +3965,28 @@ namespace Mono.CSharp {
                {
                        throw new NotSupportedException ();
                }
-               
-               public void EmitCall (EmitContext ec, Arguments arguments)
+
+               public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
                {
                        var call = new CallEmitter ();
                        call.InstanceExpression = InstanceExpression;
-                       call.Emit (ec, best_candidate, arguments, loc);                 
+                       call.ConditionalAccess = ConditionalAccess;
+
+                       if (statement)
+                               call.EmitStatement (ec, best_candidate, arguments, loc);
+                       else
+                               call.Emit (ec, best_candidate, arguments, loc);
+               }
+
+               public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
+               {
+                       ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
+                               Statement = statement
+                       };
+
+                       EmitCall (ec, arguments, statement);
+
+                       ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
                }
 
                public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
@@ -3901,8 +4036,15 @@ namespace Mono.CSharp {
 
                        // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
                        best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
-                       if (best_candidate == null)
-                               return r.BestCandidateIsDynamic ? this : null;
+                       if (best_candidate == null) {
+                               if (!r.BestCandidateIsDynamic)
+                                       return null;
+
+                               if (simple_name != null && ec.IsStatic)
+                                       InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
+
+                               return this;
+                       }
 
                        // Overload resolver had to create a new method group, all checks bellow have already been executed
                        if (r.BestCandidateNewMethodGroup != null)
@@ -3913,7 +4055,7 @@ namespace Mono.CSharp {
                                        if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
                                                InstanceExpression = null;
                                        } else {
-                                               if (best_candidate.IsStatic && simple_name != null) {
+                                               if (simple_name != null && best_candidate.IsStatic) {
                                                        InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
                                                }
 
@@ -4040,7 +4182,8 @@ namespace Mono.CSharp {
                        ProbingOnly     = 1 << 1,
                        CovariantDelegate = 1 << 2,
                        NoBaseMembers = 1 << 3,
-                       BaseMembersIncluded = 1 << 4
+                       BaseMembersIncluded = 1 << 4,
+                       GetEnumeratorLookup = 1 << 5
                }
 
                public interface IBaseMembersProvider
@@ -4241,7 +4384,6 @@ namespace Mono.CSharp {
                                if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
                                        return 0;
 
-                               var orig_p = p;
                                p = p_m.ReturnType;
                                var orig_q = q;
                                q = q_m.ReturnType;
@@ -4271,33 +4413,34 @@ namespace Mono.CSharp {
                                                q = q.TypeArguments[0];
                                                p = p.TypeArguments[0];
                                        }
-                               } else if (q != p) {
+                               }
+
+                               if (q != p) {
                                        //
-                                       // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
+                                       // An inferred return type X exists for E in the context of that parameter list, and 
+                                       // the conversion from X to Y1 is better than the conversion from X to Y2
                                        //
-                                       if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
-                                               var am_rt = am.InferReturnType (ec, null, orig_q);
-                                               if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
-                                                       return 2;
-                                       } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
-                                               var am_rt = am.InferReturnType (ec, null, orig_p);
-                                               if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
-                                                       return 1;
+                                       argument_type = am.InferReturnType (ec, null, orig_q);
+                                       if (argument_type == null) {
+                                               // TODO: Can this be hit?
+                                               return 1;
                                        }
+
+                                       if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
+                                               argument_type = ec.BuiltinTypes.Object;
                                }
+                       }
 
-                               //
-                               // The parameters are identicial and return type is not void, use better type conversion
-                               // on return type to determine better one
-                               //
-                       } else {
-                               if (argument_type == p)
-                                       return 1;
+                       if (argument_type == p)
+                               return 1;
 
-                               if (argument_type == q)
-                                       return 2;
-                       }
+                       if (argument_type == q)
+                               return 2;
 
+                       //
+                       // The parameters are identicial and return type is not void, use better type conversion
+                       // on return type to determine better one
+                       //
                        return BetterTypeConversion (ec, p, q);
                }
 
@@ -4598,11 +4741,23 @@ namespace Mono.CSharp {
                // one being the virtual base for the parameter types and modifiers.
                //
                // A return value rates candidate method compatibility,
-               // 0 = the best, int.MaxValue = the worst
                // -1 = fatal error
+               // 0 = the best, int.MaxValue = the worst
                //
-               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)
+               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)
                {
+                       //
+                       // Each step has allocated 10 values, it can overflow for
+                       // more than 10 arguments but that's ok as it's used for
+                       // better error reporting only
+                       //
+                       const int ArgumentCountMismatch         = 1000000000;
+                       const int NamedArgumentsMismatch        = 100000000;
+                       const int DefaultArgumentMismatch       = 10000000;
+                       const int UnexpectedTypeArguments       = 1000000;
+                       const int TypeArgumentsMismatch         = 100000;
+                       const int InflatedTypesMismatch         = 10000;
+
                        // Parameters of most-derived type used mainly for named and optional parameters
                        var pd = pm.Parameters;
 
@@ -4635,17 +4790,17 @@ namespace Mono.CSharp {
                                                        param_count--;
                                        } else if (arg_count > param_count) {
                                                int args_gap = System.Math.Abs (arg_count - param_count);
-                                               return int.MaxValue - 10000 + args_gap;
+                                               return ArgumentCountMismatch + args_gap;
                                        } else if (arg_count < param_count - optional_count) {
                                                int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
-                                               return int.MaxValue - 10000 + args_gap;
+                                               return ArgumentCountMismatch + args_gap;
                                        }
                                } else if (arg_count != param_count) {
                                        int args_gap = System.Math.Abs (arg_count - param_count);
                                        if (!cpd.HasParams)
-                                               return int.MaxValue - 10000 + args_gap;
+                                               return ArgumentCountMismatch + args_gap;
                                        if (arg_count < param_count - 1)
-                                               return int.MaxValue - 10000 + args_gap;
+                                               return ArgumentCountMismatch + args_gap;
                                }
 
                                // Resize to fit optional arguments
@@ -4682,7 +4837,7 @@ namespace Mono.CSharp {
 
                                                        // Named parameter not found
                                                        if (index < 0)
-                                                               return (i + 1) * 3;
+                                                               return NamedArgumentsMismatch - i;
 
                                                        // already reordered
                                                        if (index == i)
@@ -4698,8 +4853,8 @@ namespace Mono.CSharp {
                                                                ++arg_count;
                                                                temp = null;
                                                        } else {
-                                                               if (index == arg_count) 
-                                                                       return (i + 1) * 3;
+                                                               if (index == arg_count)
+                                                                       return NamedArgumentsMismatch - i - 1;
 
                                                                temp = arguments [index];
 
@@ -4736,7 +4891,7 @@ namespace Mono.CSharp {
                        // Don't do any expensive checks when the candidate cannot succeed
                        //
                        if (arg_count != param_count && !cpd.HasParams)
-                               return (param_count - arg_count) * 2 + 1;
+                               return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
 
                        var dep = candidate.GetMissingDependencies ();
                        if (dep != null) {
@@ -4753,7 +4908,7 @@ namespace Mono.CSharp {
                                if (type_arguments != null) {
                                        var g_args_count = ms.Arity;
                                        if (g_args_count != type_arguments.Count)
-                                               return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
+                                               return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
 
                                        if (type_arguments.Arguments != null)
                                                ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
@@ -4785,7 +4940,7 @@ namespace Mono.CSharp {
                                        TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
 
                                        if (i_args == null)
-                                               return ti.InferenceScore - 20000;
+                                               return TypeArgumentsMismatch - ti.InferenceScore;
 
                                        //
                                        // Clear any error messages when the result was success
@@ -4794,6 +4949,14 @@ namespace Mono.CSharp {
                                                lambda_conv_msgs.ClearSession ();
 
                                        if (i_args.Length != 0) {
+                                               if (!errorMode) {
+                                                       for (int i = 0; i < i_args.Length; ++i) {
+                                                               var ta = i_args [i];
+                                                               if (!ta.IsAccessible (ec))
+                                                                       return TypeArgumentsMismatch - i;
+                                                       }
+                                               }
+
                                                ms = ms.MakeGenericMethod (ec, i_args);
                                        }
                                }
@@ -4803,7 +4966,7 @@ namespace Mono.CSharp {
                                //
                                if (!CheckInflatedArguments (ms)) {
                                        candidate = ms;
-                                       return int.MaxValue - 25000;
+                                       return InflatedTypesMismatch;
                                }
 
                                //
@@ -4826,7 +4989,7 @@ namespace Mono.CSharp {
                                ptypes = pd.Types;
                        } else {
                                if (type_arguments != null)
-                                       return int.MaxValue - 15000;
+                                       return UnexpectedTypeArguments;
 
                                ptypes = cpd.Types;
                        }
@@ -4891,7 +5054,7 @@ namespace Mono.CSharp {
 
                                score = 1;
                                if (!params_expanded_form) {
-                                       if (a.ArgType == Argument.AType.ExtensionType) {
+                                       if (a.IsExtensionType) {
                                                //
                                                // Indentity, implicit reference or boxing conversion must exist for the extension parameter
                                                //
@@ -4987,31 +5150,36 @@ namespace Mono.CSharp {
                        // is used and argument is not of dynamic type
                        //
                        if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
-                               if (argument.Type != parameter) {
+                               var arg_type = argument.Type;
+
+                               if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
+                                       //
+                                       // Using dynamic for ref/out parameter can still succeed at runtime
+                                       //
+                                       if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
+                                               return -1;
+
+                                       return 1;
+                               }
+
+                               if (arg_type != parameter) {
+                                       if (arg_type == InternalType.VarOutType)
+                                               return 0;
+
                                        //
                                        // Do full equality check after quick path
                                        //
-                                       if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
+                                       if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
                                                //
                                                // Using dynamic for ref/out parameter can still succeed at runtime
                                                //
-                                               if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
+                                               if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
                                                        return -1;
 
                                                return 2;
                                        }
                                }
 
-                               if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
-                                       //
-                                       // Using dynamic for ref/out parameter can still succeed at runtime
-                                       //
-                                       if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
-                                               return -1;
-
-                                       return 1;
-                               }
-
                        } else {
                                if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
                                        return -1;
@@ -5147,7 +5315,7 @@ namespace Mono.CSharp {
                                                bool params_expanded_form = false;
                                                bool dynamic_argument = false;
                                                TypeSpec rt = pm.MemberType;
-                                               int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
+                                               int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
 
                                                if (lambda_conv_msgs != null)
                                                        lambda_conv_msgs.EndSession ();
@@ -5161,13 +5329,17 @@ namespace Mono.CSharp {
                                                        if (candidate_rate < 0)
                                                                return null;
 
-                                                       best_candidate_rate = candidate_rate;
-                                                       best_candidate = member;
-                                                       best_candidate_args = candidate_args;
-                                                       best_candidate_params = params_expanded_form;
-                                                       best_candidate_dynamic = dynamic_argument;
-                                                       best_parameter_member = pm;
-                                                       best_candidate_return_type = rt;
+                                                       if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
+                                                               // Only parameterless methods are considered
+                                                       } else {
+                                                               best_candidate_rate = candidate_rate;
+                                                               best_candidate = member;
+                                                               best_candidate_args = candidate_args;
+                                                               best_candidate_params = params_expanded_form;
+                                                               best_candidate_dynamic = dynamic_argument;
+                                                               best_parameter_member = pm;
+                                                               best_candidate_return_type = rt;
+                                                       }
                                                } else if (candidate_rate == 0) {
                                                        //
                                                        // The member look is done per type for most operations but sometimes
@@ -5275,7 +5447,7 @@ namespace Mono.CSharp {
                        }
 
                        if (best_candidate_dynamic) {
-                               if (args[0].ArgType == Argument.AType.ExtensionType) {
+                               if (args[0].IsExtensionType) {
                                        rc.Report.Error (1973, loc,
                                                "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",
                                                args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
@@ -5521,6 +5693,9 @@ namespace Mono.CSharp {
                                break;
                        }
 
+                       if (args == null)
+                               return false;
+
                        foreach (var arg in args) {
                                var na = arg as NamedArgument;
                                if (na == null)
@@ -5541,7 +5716,8 @@ namespace Mono.CSharp {
                bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
                {
                        var pd = pm.Parameters;
-                       TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
+                       var cpd = ((IParametersMember) member).Parameters;
+                       var ptypes = cpd.Types;
 
                        Parameter.Modifier p_mod = 0;
                        TypeSpec pt = null;
@@ -5557,7 +5733,7 @@ namespace Mono.CSharp {
                                        continue;
 
                                if (p_mod != Parameter.Modifier.PARAMS) {
-                                       p_mod = pd.FixedParameters[a_idx].ModFlags;
+                                       p_mod = cpd.FixedParameters [a_idx].ModFlags;
                                        pt = ptypes[a_idx];
                                        has_unsafe_arg |= pt.IsPointer;
 
@@ -5576,10 +5752,20 @@ namespace Mono.CSharp {
                                        if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
                                                break;
 
-                                       if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
+                                       var arg_type = a.Type;
+                                       if (arg_type == pt)
                                                continue;
 
-                                       break;
+                                       if (arg_type == InternalType.VarOutType) {
+                                               //
+                                               // Set underlying variable type based on parameter type
+                                               //
+                                               ((DeclarationExpression)a.Expr).Variable.Type = pt;
+                                               continue;
+                                       }
+
+                                       if (!TypeSpecComparer.IsEqual (arg_type, pt))
+                                               break;
                                }
 
                                NamedArgument na = a as NamedArgument;
@@ -5618,7 +5804,7 @@ namespace Mono.CSharp {
                                }
 
                                Expression conv;
-                               if (a.ArgType == Argument.AType.ExtensionType) {
+                               if (a.IsExtensionType) {
                                        if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
                                                conv = a.Expr;
                                        } else {
@@ -5651,6 +5837,20 @@ namespace Mono.CSharp {
                        }
 
                        if (a_idx != arg_count) {
+                               //
+                               // Convert all var out argument to error type for less confusing error reporting
+                               // when no matching overload is found
+                               //
+                               for (; a_idx < arg_count; a_idx++) {
+                                       var arg = args [a_idx];
+                                       if (arg == null)
+                                               continue;
+
+                                       if (arg.Type == InternalType.VarOutType) {
+                                               ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
+                                       }
+                               }
+
                                ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
                                return false;
                        }
@@ -5658,7 +5858,7 @@ namespace Mono.CSharp {
                        //
                        // Fill not provided arguments required by params modifier
                        //
-                       if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
+                       if (params_initializers == null && arg_count + 1 == pd.Count) {
                                if (args == null)
                                        args = new Arguments (1);
 
@@ -5872,6 +6072,10 @@ namespace Mono.CSharp {
 
                public override Expression CreateExpressionTree (ResolveContext ec)
                {
+                       if (ConditionalAccess) {
+                               Error_NullShortCircuitInsideExpressionTree (ec);
+                       }
+
                        return CreateExpressionTree (ec, true);
                }
 
@@ -5914,6 +6118,8 @@ namespace Mono.CSharp {
                        bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
 
                        if (rhs != this) {
+                               ResolveConditionalAccessReceiver (ec);
+
                                if (ResolveInstanceExpression (ec, rhs)) {
                                        // Resolve the field's instance expression while flow analysis is turned
                                        // off: when accessing a field "a.b", we must check whether the field
@@ -5935,6 +6141,9 @@ namespace Mono.CSharp {
                                }
 
                                DoBestMemberChecks (ec, spec);
+
+                               if (conditional_access_receiver)
+                                       ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
                        }
 
                        var fb = spec as FixedFieldSpec;
@@ -5965,6 +6174,14 @@ namespace Mono.CSharp {
                                variable_info = var.VariableInfo.GetStructFieldInfo (Name);
                        }
 
+                       if (ConditionalAccess) {
+                               if (conditional_access_receiver)
+                                       type = LiftMemberType (ec, type);
+
+                               if (InstanceExpression.IsNull)
+                                       return Constant.CreateConstantFromValue (type, null, loc);
+                       }
+
                        eclass = ExprClass.Variable;
                        return this;
                }
@@ -6059,8 +6276,11 @@ namespace Mono.CSharp {
                        return null;
                }
 
-               override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
+               public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
                {
+                       if (ConditionalAccess)
+                               throw new NotSupportedException ("null propagating operator assignment");
+
                        if (spec is FixedFieldSpec) {
                                // It could be much better error message but we want to be error compatible
                                Error_ValueAssignment (ec, right_side);
@@ -6120,11 +6340,14 @@ namespace Mono.CSharp {
                                        return;
                                }
 
-                               if (TypeSpec.IsValueType (InstanceExpression.Type))
+                               if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
                                        return;
                        }
 
                        base.FlowAnalysis (fc);
+
+                       if (conditional_access_receiver)
+                               fc.ConditionalAccessEnd ();
                }
 
                public override int GetHashCode ()
@@ -6171,8 +6394,12 @@ namespace Mono.CSharp {
 
                                ec.Emit (OpCodes.Ldsfld, spec);
                        } else {
-                               if (!prepared)
+                               if (!prepared) {
+                                       if (conditional_access_receiver)
+                                               ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
+
                                        EmitInstance (ec, false);
+                               }
 
                                // Optimization for build-in types
                                if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
@@ -6189,6 +6416,10 @@ namespace Mono.CSharp {
                                                ec.Emit (OpCodes.Ldfld, spec);
                                        }
                                }
+
+                               if (conditional_access_receiver) {
+                                       ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
+                               }
                        }
 
                        if (leave_copy) {
@@ -6203,16 +6434,14 @@ namespace Mono.CSharp {
                public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
                {
                        bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
-                       if (isCompound && !(source is DynamicExpressionStatement)) {
-                               if (has_await_source) {
-                                       if (IsInstance)
-                                               InstanceExpression = InstanceExpression.EmitToField (ec);
-                               } else {
-                                       prepared = true;
-                               }
+                       if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
+                               prepared = true;
                        }
 
                        if (IsInstance) {
+                               if (ConditionalAccess)
+                                       throw new NotImplementedException ("null operator assignment");
+
                                if (has_await_source)
                                        source = source.EmitToField (ec);
 
@@ -6221,7 +6450,7 @@ namespace Mono.CSharp {
 
                        source.Emit (ec);
 
-                       if (leave_copy) {
+                       if (leave_copy || ec.NotifyEvaluatorOnStore) {
                                ec.Emit (OpCodes.Dup);
                                if (!IsStatic) {
                                        temp = new LocalTemporary (this.Type);
@@ -6238,6 +6467,16 @@ namespace Mono.CSharp {
                                ec.Emit (OpCodes.Stsfld, spec);
                        else
                                ec.Emit (OpCodes.Stfld, spec);
+
+                       if (ec.NotifyEvaluatorOnStore) {
+                               if (!IsStatic)
+                                       throw new NotImplementedException ("instance field write");
+
+                               if (leave_copy)
+                                       ec.Emit (OpCodes.Dup);
+
+                               ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
+                       }
                        
                        if (temp != null) {
                                temp.Emit (ec);
@@ -6425,6 +6664,10 @@ namespace Mono.CSharp {
 
                public override Expression CreateExpressionTree (ResolveContext ec)
                {
+                       if (ConditionalAccess) {
+                               Error_NullShortCircuitInsideExpressionTree (ec);
+                       }
+
                        Arguments args;
                        if (IsSingleDimensionalArrayLength ()) {
                                args = new Arguments (1);
@@ -6492,9 +6735,19 @@ namespace Mono.CSharp {
                        // Special case: length of single dimension array property is turned into ldlen
                        //
                        if (IsSingleDimensionalArrayLength ()) {
+                               if (conditional_access_receiver) {
+                                       ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
+                               }
+
                                EmitInstance (ec, false);
+
                                ec.Emit (OpCodes.Ldlen);
                                ec.Emit (OpCodes.Conv_I4);
+
+                               if (conditional_access_receiver) {
+                                       ec.CloseConditionalAccess (type);
+                               }
+
                                return;
                        }
 
@@ -6551,7 +6804,14 @@ namespace Mono.CSharp {
                        if (args == null)
                                call.InstanceExpressionOnStack = true;
 
-                       call.Emit (ec, Setter, args, loc);
+                       if (ConditionalAccess) {
+                               call.ConditionalAccess = true;
+                       }
+
+                       if (leave_copy)
+                               call.Emit (ec, Setter, args, loc);
+                       else
+                               call.EmitStatement (ec, Setter, args, loc);
 
                        if (temp != null) {
                                temp.Emit (ec);
@@ -6563,6 +6823,14 @@ namespace Mono.CSharp {
                        }
                }
 
+               public override void FlowAnalysis (FlowAnalysisContext fc)
+               {
+                       base.FlowAnalysis (fc);
+
+                       if (conditional_access_receiver)
+                               fc.ConditionalAccessEnd ();
+               }
+
                protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
                {
                        eclass = ExprClass.PropertyAccess;
@@ -6649,12 +6917,19 @@ namespace Mono.CSharp {
                protected override Expression DoResolve (ResolveContext ec)
                {
                        if (eclass == ExprClass.Unresolved) {
+                               ResolveConditionalAccessReceiver (ec);
+
                                var expr = OverloadResolve (ec, null);
                                if (expr == null)
                                        return null;
 
                                if (expr != this)
                                        return expr.Resolve (ec);
+
+                               if (conditional_access_receiver) {
+                                       type = LiftMemberType (ec, type);
+                                       ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
+                               }
                        }
 
                        if (!ResolveGetter (ec))
@@ -6665,6 +6940,9 @@ namespace Mono.CSharp {
 
                public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
                {
+                       if (ConditionalAccess)
+                               throw new NotSupportedException ("null propagating operator assignment");
+
                        if (right_side == EmptyExpression.OutAccess) {
                                // TODO: best_candidate can be null at this point
                                INamedBlockVariable variable = null;
@@ -6694,19 +6972,32 @@ namespace Mono.CSharp {
                        return this;
                }
 
+               void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
+               {
+                       ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
+
+                       call.Emit (ec, method, arguments, loc);
+
+                       ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
+               }
+
                //
                // Implements the IAssignMethod interface for assignments
                //
                public virtual void Emit (EmitContext ec, bool leave_copy)
                {
                        var call = new CallEmitter ();
+                       call.ConditionalAccess = ConditionalAccess;
                        call.InstanceExpression = InstanceExpression;
                        if (has_await_arguments)
                                call.HasAwaitArguments = true;
                        else
                                call.DuplicateArguments = emitting_compound_assignment;
 
-                       call.Emit (ec, Getter, Arguments, loc);
+                       if (conditional_access_receiver)
+                               EmitConditionalAccess (ec, ref call, Getter, Arguments);
+                       else
+                               call.Emit (ec, Getter, Arguments, loc);
 
                        if (call.HasAwaitArguments) {
                                InstanceExpression = call.InstanceExpression;
@@ -6935,9 +7226,18 @@ namespace Mono.CSharp {
                        Arguments args = new Arguments (1);
                        args.Add (new Argument (source));
 
+                       // TODO: Wrong, needs receiver
+//                     if (NullShortCircuit) {
+//                             ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
+//                     }
+
                        var call = new CallEmitter ();
                        call.InstanceExpression = InstanceExpression;
-                       call.Emit (ec, op, args, loc);
+                       call.ConditionalAccess = ConditionalAccess;
+                       call.EmitStatement (ec, op, args, loc);
+
+//                     if (NullShortCircuit)
+//                             ec.CloseConditionalAccess (null);
                }
 
                #endregion