Merge pull request #1063 from esdrubal/bug18482
[mono.git] / mcs / mcs / ecore.cs
index 0b73b3656cbdf5ace5d59645ffb7b33c81999ef3..97fe44d239d5dc4213cce585784c0fbeab194858 100644 (file)
@@ -429,6 +429,18 @@ namespace Mono.CSharp {
                {
                        return type.GetDefinition ().GetSignatureForError ();
                }
+
+               protected static bool IsNullPropagatingValid (TypeSpec type)
+               {
+                       return (TypeSpec.IsReferenceType (type) && type != InternalType.NullLiteral) || type.IsNullableType;
+               }
+
+               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.
@@ -540,10 +552,16 @@ namespace Mono.CSharp {
                        return c;
                }
 
-               public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
+               public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
                {
-                       rc.Module.Compiler.Report.Error (182, loc,
-                               "An attribute argument must be a constant expression, typeof expression or array creation expression");
+                       if (Attribute.IsValidArgumentType (parameterType)) {
+                               rc.Module.Compiler.Report.Error (182, loc,
+                                       "An attribute argument must be a constant expression, typeof expression or array creation expression");
+                       } else {
+                               rc.Module.Compiler.Report.Error (181, loc,
+                                       "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
+                                       targetType.GetSignatureForError ());
+                       }
                }
 
                /// <summary>
@@ -930,6 +948,11 @@ 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)
                {
                }
@@ -1582,9 +1605,9 @@ namespace Mono.CSharp {
                        Child.Emit (ec);
                }
 
-               public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
+               public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
                {
-                       Child.EncodeAttributeValue (rc, enc, Child.Type);
+                       Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
                }
 
                public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
@@ -1702,16 +1725,16 @@ namespace Mono.CSharp {
                        return this;
                }
 
-               public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
+               public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
                {
                        // Only boxing to object type is supported
                        if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
-                               base.EncodeAttributeValue (rc, enc, targetType);
+                               base.EncodeAttributeValue (rc, enc, targetType, parameterType);
                                return;
                        }
 
                        enc.Encode (child.Type);
-                       child.EncodeAttributeValue (rc, enc, child.Type);
+                       child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
                }
 
                public override void Emit (EmitContext ec)
@@ -2113,15 +2136,15 @@ namespace Mono.CSharp {
                                return c;
                        }
 
-                       public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
+                       public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
                        {
                                //
                                // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
                                //
                                if (orig_expr is Conditional)
-                                       child.EncodeAttributeValue (rc, enc, targetType);
+                                       child.EncodeAttributeValue (rc, enc, targetType,parameterType);
                                else
-                                       base.EncodeAttributeValue (rc, enc, targetType);
+                                       base.EncodeAttributeValue (rc, enc, targetType, parameterType);
                        }
                }
 
@@ -2754,6 +2777,15 @@ namespace Mono.CSharp {
                                        }
                                }
 
+                               var mg = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
+                               if (mg != null) {
+                                       if (Arity > 0) {
+                                               targs.Resolve (rc);
+                                               mg.SetTypeArguments (rc, targs);
+                                       }
+                                       return mg;
+                               }
+
                                if (errorMode) {
                                        if (variable_found) {
                                                rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
@@ -3136,6 +3168,8 @@ namespace Mono.CSharp {
                        get;
                }
 
+               public bool NullShortCircuit { get; set; }
+
                protected abstract TypeSpec DeclaringType {
                        get;
                }
@@ -3341,7 +3375,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))
@@ -3416,14 +3450,25 @@ namespace Mono.CSharp {
 
                        if (InstanceExpression == null || InstanceExpression is TypeExpr) {
                                if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
-                                       if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
+                                       if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
                                                rc.Report.Error (236, loc,
                                                        "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
                                                        GetSignatureForError ());
-                                       else
-                                               rc.Report.Error (120, loc,
-                                                       "An object reference is required to access non-static member `{0}'",
-                                                       GetSignatureForError ());
+                                       } else {
+                                               var fe = this as FieldExpr;
+                                               if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
+                                                       if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
+                                                               rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
+                                                       } else  {
+                                                               rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
+                                                                       fe.Name);
+                                                       }
+                                               } else {
+                                                       rc.Report.Error (120, loc,
+                                                               "An object reference is required to access non-static member `{0}'",
+                                                               GetSignatureForError ());
+                                               }
+                                       }
 
                                        InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
                                        return false;
@@ -3468,7 +3513,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 && !NullShortCircuit && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
                                ec.Report.Warning (1720, 1, left.Location,
                                        "Expression will always cause a `{0}'", "System.NullReferenceException");
                        }
@@ -3477,30 +3522,16 @@ namespace Mono.CSharp {
                        return this;
                }
 
-               protected void EmitInstance (EmitContext ec, bool prepare_for_load)
+               protected InstanceEmitter 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.NullShortCircuit = NullShortCircuit;
+                       inst.Emit (ec);
 
                        if (prepare_for_load)
                                ec.Emit (OpCodes.Dup);
+
+                       return inst;
                }
 
                public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
@@ -3797,7 +3828,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 (NullShortCircuit)
+                               Error_NullShortCircuitInsideExpressionTree (ec);
+
                        return new TypeOfMethod (best_candidate, loc);
                }
                
@@ -3819,11 +3853,15 @@ 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.NullShortCircuit = NullShortCircuit;
+                       if (statement)
+                               call.EmitStatement (ec, best_candidate, arguments, loc);
+                       else
+                               call.Emit (ec, best_candidate, arguments, loc);
                }
 
                public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
@@ -3873,8 +3911,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)
@@ -3885,7 +3930,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);
                                                }
 
@@ -3923,6 +3968,9 @@ namespace Mono.CSharp {
                        if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
                                Methods = Excluded;
 
+                       if (NullShortCircuit)
+                               best_candidate_return = LiftMemberType (ec, best_candidate_return);
+
                        return this;
                }
 
@@ -4012,7 +4060,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
@@ -4213,7 +4262,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;
@@ -4243,33 +4291,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);
                }
 
@@ -4455,7 +4504,7 @@ namespace Mono.CSharp {
                        //
                        // We have not reached end of parameters list due to params or used default parameters
                        //
-                       if (j < candidate_pd.Count && j < best_pd.Count) {
+                       while (j < candidate_pd.Count && j < best_pd.Count) {
                                var cand_param = candidate_pd.FixedParameters [j];
                                var best_param = best_pd.FixedParameters [j];
 
@@ -4463,11 +4512,16 @@ namespace Mono.CSharp {
                                        //
                                        // LAMESPEC:
                                        //
-                                       // void Foo (params int[]) is better than void Foo (int i = 0) for Foo ()
-                                       // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null)
+                                       // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
+                                       // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
                                        //
                                        if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
-                                               return !candidate_params;
+                                               return cand_param.HasDefaultValue;
+
+                                       if (cand_param.HasDefaultValue) {
+                                               ++j;
+                                               continue;
+                                       }
                                } else {
                                        //
                                        // Neither is better when not all arguments are provided
@@ -4479,6 +4533,8 @@ namespace Mono.CSharp {
                                        if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
                                                return false;
                                }
+
+                               break;
                        }
 
                        if (candidate_pd.Count != best_pd.Count)
@@ -4566,7 +4622,7 @@ namespace Mono.CSharp {
                // 0 = the best, int.MaxValue = the worst
                // -1 = fatal error
                //
-               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)
                {
                        // Parameters of most-derived type used mainly for named and optional parameters
                        var pd = pm.Parameters;
@@ -4663,7 +4719,10 @@ namespace Mono.CSharp {
                                                                ++arg_count;
                                                                temp = null;
                                                        } else {
-                                                               temp = arguments[index];
+                                                               if (index == arg_count) 
+                                                                       return (i + 1) * 3;
+
+                                                               temp = arguments [index];
 
                                                                // The slot has been taken by positional argument
                                                                if (temp != null && !(temp is NamedArgument))
@@ -4756,6 +4815,13 @@ namespace Mono.CSharp {
                                                lambda_conv_msgs.ClearSession ();
 
                                        if (i_args.Length != 0) {
+                                               if (!errorMode) {
+                                                       foreach (var ta in i_args) {
+                                                               if (!ta.IsAccessible (ec))
+                                                                       return ti.InferenceScore - 10000;
+                                                       }
+                                               }
+
                                                ms = ms.MakeGenericMethod (ec, i_args);
                                        }
                                }
@@ -5109,7 +5175,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 ();
@@ -5123,13 +5189,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
@@ -5413,8 +5483,7 @@ namespace Mono.CSharp {
                        // For candidates which match on parameters count report more details about incorrect arguments
                        //
                        if (pm != null) {
-                               int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
-                               if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
+                               if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
                                        // Reject any inaccessible member
                                        if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
                                                rc.Report.SymbolRelatedToPreviousError (best_candidate);
@@ -5468,10 +5537,47 @@ namespace Mono.CSharp {
                        }
                }
 
+               static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
+               {
+                       var p = ((IParametersMember)best_candidate).Parameters;
+                       if (!p.HasParams)
+                               return false;
+
+                       string name = null;
+                       for (int i = p.Count - 1; i != 0; --i) {
+                               var fp = p.FixedParameters [i];
+                               if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
+                                       continue;
+
+                               name = fp.Name;
+                               break;
+                       }
+
+                       if (args == null)
+                               return false;
+
+                       foreach (var arg in args) {
+                               var na = arg as NamedArgument;
+                               if (na == null)
+                                       continue;
+
+                               if (na.Name == name) {
+                                       name = null;
+                                       break;
+                               }
+                       }
+
+                       if (name == null)
+                               return false;
+
+                       return args.Count + 1 == pm.Parameters.Count;
+               }
+
                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;
@@ -5487,7 +5593,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;
 
@@ -5588,7 +5694,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);
 
@@ -5802,6 +5908,10 @@ namespace Mono.CSharp {
 
                public override Expression CreateExpressionTree (ResolveContext ec)
                {
+                       if (NullShortCircuit) {
+                               Error_NullShortCircuitInsideExpressionTree (ec);
+                       }
+
                        return CreateExpressionTree (ec, true);
                }
 
@@ -5895,6 +6005,13 @@ namespace Mono.CSharp {
                                variable_info = var.VariableInfo.GetStructFieldInfo (Name);
                        }
 
+                       if (NullShortCircuit) {
+                               type = LiftMemberType (ec, type);
+
+                               if (InstanceExpression.IsNull)
+                                       return Constant.CreateConstantFromValue (type, null, loc);
+                       }
+
                        eclass = ExprClass.Variable;
                        return this;
                }
@@ -5989,8 +6106,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 (NullShortCircuit)
+                               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);
@@ -6050,7 +6170,7 @@ namespace Mono.CSharp {
                                        return;
                                }
 
-                               if (TypeSpec.IsValueType (InstanceExpression.Type))
+                               if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
                                        return;
                        }
 
@@ -6101,8 +6221,11 @@ namespace Mono.CSharp {
 
                                ec.Emit (OpCodes.Ldsfld, spec);
                        } else {
+                               InstanceEmitter ie;
                                if (!prepared)
-                                       EmitInstance (ec, false);
+                                       ie = EmitInstance (ec, false);
+                               else
+                                       ie = new InstanceEmitter ();
 
                                // Optimization for build-in types
                                if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
@@ -6117,6 +6240,10 @@ namespace Mono.CSharp {
                                                        ec.Emit (OpCodes.Volatile);
 
                                                ec.Emit (OpCodes.Ldfld, spec);
+
+                                               if (NullShortCircuit) {
+                                                       ie.EmitResultLift (ec, spec.MemberType, false);
+                                               }
                                        }
                                }
                        }
@@ -6133,16 +6260,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 (NullShortCircuit)
+                                       throw new NotImplementedException ("null operator assignment");
+
                                if (has_await_source)
                                        source = source.EmitToField (ec);
 
@@ -6151,7 +6276,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);
@@ -6168,6 +6293,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);
@@ -6230,7 +6365,6 @@ namespace Mono.CSharp {
                                var temp = ec.GetTemporaryLocal (type);
                                ec.Emit (OpCodes.Stloc, temp);
                                ec.Emit (OpCodes.Ldloca, temp);
-                               ec.FreeTemporaryLocal (temp, type);
                                return;
                        }
 
@@ -6356,6 +6490,10 @@ namespace Mono.CSharp {
 
                public override Expression CreateExpressionTree (ResolveContext ec)
                {
+                       if (NullShortCircuit) {
+                               Error_NullShortCircuitInsideExpressionTree (ec);
+                       }
+
                        Arguments args;
                        if (IsSingleDimensionalArrayLength ()) {
                                args = new Arguments (1);
@@ -6423,9 +6561,14 @@ namespace Mono.CSharp {
                        // Special case: length of single dimension array property is turned into ldlen
                        //
                        if (IsSingleDimensionalArrayLength ()) {
-                               EmitInstance (ec, false);
+                               var inst = EmitInstance (ec, false);
+
                                ec.Emit (OpCodes.Ldlen);
                                ec.Emit (OpCodes.Conv_I4);
+
+                               if (NullShortCircuit)
+                                       inst.EmitResultLift (ec, ec.BuiltinTypes.Int, false);
+
                                return;
                        }
 
@@ -6481,8 +6624,15 @@ namespace Mono.CSharp {
                        call.InstanceExpression = InstanceExpression;
                        if (args == null)
                                call.InstanceExpressionOnStack = true;
+                       if (NullShortCircuit) {
+                               call.NullShortCircuit = true;
+                               call.NullOperatorLabel = null_operator_label;
+                       }
 
-                       call.Emit (ec, Setter, args, loc);
+                       if (leave_copy)
+                               call.Emit (ec, Setter, args, loc);
+                       else
+                               call.EmitStatement (ec, Setter, args, loc);
 
                        if (temp != null) {
                                temp.Emit (ec);
@@ -6547,6 +6697,7 @@ namespace Mono.CSharp {
                protected LocalTemporary temp;
                protected bool emitting_compound_assignment;
                protected bool has_await_arguments;
+               protected Label null_operator_label;
 
                protected PropertyOrIndexerExpr (Location l)
                {
@@ -6584,6 +6735,10 @@ namespace Mono.CSharp {
                                if (expr == null)
                                        return null;
 
+                               if (NullShortCircuit && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
+                                       type = LiftMemberType (ec, type);
+                               }
+
                                if (expr != this)
                                        return expr.Resolve (ec);
                        }
@@ -6596,6 +6751,9 @@ namespace Mono.CSharp {
 
                public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
                {
+                       if (NullShortCircuit)
+                               throw new NotSupportedException ("null propagating operator assignment");
+
                        if (right_side == EmptyExpression.OutAccess) {
                                // TODO: best_candidate can be null at this point
                                INamedBlockVariable variable = null;
@@ -6621,7 +6779,15 @@ namespace Mono.CSharp {
 
                        if (!ResolveSetter (ec))
                                return null;
-
+/*
+                       if (NullShortCircuit && ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
+                               var lifted_type = LiftMemberType (ec, type);
+                               if (type != lifted_type) {
+                                       // TODO: Workaround to disable codegen for now
+                                       return Nullable.Wrap.Create (this, lifted_type);
+                               }
+                       }
+*/
                        return this;
                }
 
@@ -6631,6 +6797,7 @@ namespace Mono.CSharp {
                public virtual void Emit (EmitContext ec, bool leave_copy)
                {
                        var call = new CallEmitter ();
+                       call.NullShortCircuit = NullShortCircuit;
                        call.InstanceExpression = InstanceExpression;
                        if (has_await_arguments)
                                call.HasAwaitArguments = true;
@@ -6645,6 +6812,9 @@ namespace Mono.CSharp {
                                has_await_arguments = true;
                        }
 
+                       if (NullShortCircuit && emitting_compound_assignment)
+                               null_operator_label = call.NullOperatorLabel;
+
                        if (leave_copy) {
                                ec.Emit (OpCodes.Dup);
                                temp = new LocalTemporary (Type);
@@ -6868,7 +7038,8 @@ namespace Mono.CSharp {
 
                        var call = new CallEmitter ();
                        call.InstanceExpression = InstanceExpression;
-                       call.Emit (ec, op, args, loc);
+                       call.NullShortCircuit = NullShortCircuit;
+                       call.EmitStatement (ec, op, args, loc);
                }
 
                #endregion